Diff to HTML by rtfpessoa

Files changed (151) hide show
  1. src/base58.h +1 -0
  2. src/bech32.cpp +2 -2
  3. src/bech32.h +1 -1
  4. src/bignum.h +582 -0
  5. src/bitcoin-cli.cpp +6 -6
  6. src/bitcoin-tx.cpp +12 -26
  7. src/bitcoind.cpp +3 -3
  8. src/blockencodings.cpp +4 -1
  9. src/blockencodings.h +3 -1
  10. src/chain.cpp +14 -6
  11. src/chain.h +119 -10
  12. src/chainparams.cpp +159 -200
  13. src/chainparams.h +3 -3
  14. src/chainparamsbase.cpp +3 -3
  15. src/clientversion.cpp +7 -3
  16. src/clientversion.h +8 -1
  17. src/coins.cpp +4 -3
  18. src/coins.h +30 -5
  19. src/consensus/amount.h +12 -2
  20. src/consensus/params.h +10 -57
  21. src/consensus/tx_check.cpp +10 -0
  22. src/consensus/tx_verify.cpp +55 -14
  23. src/consensus/tx_verify.h +6 -1
  24. src/core_write.cpp +6 -3
  25. src/deploymentstatus.cpp +0 -34
  26. src/deploymentstatus.h +0 -55
  27. src/dummywallet.cpp +0 -2
  28. src/gen_ecmult_gen_static_prec_table.c +83 -0
  29. src/gen_ecmult_static_pre_g.c +131 -0
  30. src/hash.cpp +9 -0
  31. src/hash.h +3 -0
  32. src/index/base.cpp +1 -1
  33. src/index/coinstatsindex.cpp +22 -22
  34. src/index/txindex.cpp +5 -0
  35. src/index/txindex.h +5 -0
  36. src/init.cpp +38 -126
  37. src/int_utils.h +290 -0
  38. src/interfaces/chain.h +4 -30
  39. src/interfaces/init.h +4 -1
  40. src/interfaces/node.h +6 -6
  41. src/interfaces/wallet.h +9 -27
  42. src/kernel.cpp +725 -0
  43. src/kernel.h +71 -0
  44. src/kernelrecord.cpp +120 -0
  45. src/kernelrecord.h +60 -0
  46. src/key.cpp +1 -1
  47. src/net.cpp +5 -0
  48. src/net.h +16 -9
  49. src/net_processing.cpp +208 -76
  50. src/netmessagemaker.h +1 -1
  51. src/node/blockstorage.cpp +19 -197
  52. src/node/blockstorage.h +3 -50
  53. src/node/chainstate.cpp +1 -13
  54. src/node/chainstate.h +0 -2
  55. src/node/context.cpp +0 -1
  56. src/node/context.h +9 -8
  57. src/node/interfaces.cpp +13 -18
  58. src/node/miner.cpp +302 -49
  59. src/node/miner.h +15 -7
  60. src/node/psbt.cpp +3 -4
  61. src/node/psbt.h +0 -2
  62. src/node/transaction.cpp +1 -11
  63. src/node/transaction.h +1 -10
  64. src/node/ui_interface.cpp +1 -1
  65. src/node/ui_interface.h +3 -1
  66. src/policy/feerate.cpp +0 -45
  67. src/policy/feerate.h +0 -75
  68. src/policy/fees.cpp +0 -1017
  69. src/policy/fees.h +0 -310
  70. src/policy/policy.cpp +2 -48
  71. src/policy/policy.h +2 -18
  72. src/policy/rbf.cpp +0 -176
  73. src/policy/rbf.h +0 -102
  74. src/policy/settings.cpp +0 -3
  75. src/policy/settings.h +1 -4
  76. src/pow.cpp +42 -52
  77. src/pow.h +1 -2
  78. src/primitives/block.cpp +5 -3
  79. src/primitives/block.h +48 -2
  80. src/primitives/transaction.cpp +9 -6
  81. src/primitives/transaction.h +29 -3
  82. src/protocol.cpp +1 -0
  83. src/protocol.h +4 -1
  84. src/psbt.h +0 -1
  85. src/rest.cpp +0 -3
  86. src/rpc/blockchain.cpp +77 -311
  87. src/rpc/blockchain.h +1 -1
  88. src/rpc/client.cpp +16 -10
  89. src/rpc/mining.cpp +81 -263
  90. src/rpc/misc.cpp +9 -9
  91. src/rpc/net.cpp +2 -3
  92. src/rpc/protocol.h +2 -0
  93. src/rpc/rawtransaction.cpp +18 -59
  94. src/rpc/rawtransaction_util.cpp +31 -11
  95. src/rpc/rawtransaction_util.h +1 -1
  96. src/rpc/server_util.cpp +0 -14
  97. src/rpc/util.cpp +2 -2
  98. src/rpc/util.h +1 -1
  99. src/script/interpreter.cpp +8 -0
  100. src/script/script.cpp +14 -0
  101. src/script/script.h +5 -1
  102. src/script/sign.cpp +4 -0
  103. src/script/standard.h +2 -2
  104. src/serialize.h +8 -4
  105. src/timedatadummy.cpp +7 -0
  106. src/txdb.cpp +17 -2
  107. src/txmempool.cpp +12 -71
  108. src/txmempool.h +3 -24
  109. src/uint256.h +5 -0
  110. src/undo.h +5 -2
  111. src/util.h +74 -0
  112. src/util/error.cpp +0 -2
  113. src/util/error.h +0 -1
  114. src/util/message.cpp +1 -1
  115. src/util/moneystr.cpp +1 -1
  116. src/util/strencodings.cpp +7 -3
  117. src/util/system.cpp +11 -10
  118. src/validation.cpp +472 -415
  119. src/validation.h +21 -17
  120. src/validationinterface.h +0 -1
  121. src/version.h +3 -2
  122. src/versionbits.cpp +0 -246
  123. src/versionbits.h +0 -107
  124. src/wallet/coincontrol.h +0 -10
  125. src/wallet/coinselection.cpp +11 -11
  126. src/wallet/coinselection.h +3 -26
  127. src/wallet/feebumper.cpp +0 -286
  128. src/wallet/feebumper.h +0 -61
  129. src/wallet/fees.cpp +0 -94
  130. src/wallet/fees.h +0 -48
  131. src/wallet/init.cpp +7 -15
  132. src/wallet/interfaces.cpp +25 -28
  133. src/wallet/receive.cpp +30 -0
  134. src/wallet/receive.h +1 -0
  135. src/wallet/rpc/addresses.cpp +13 -13
  136. src/wallet/rpc/backup.cpp +4 -125
  137. src/wallet/rpc/coins.cpp +7 -7
  138. src/wallet/rpc/encrypt.cpp +17 -4
  139. src/wallet/rpc/spend.cpp +21 -292
  140. src/wallet/rpc/transactions.cpp +20 -19
  141. src/wallet/rpc/util.cpp +3 -0
  142. src/wallet/rpc/wallet.cpp +262 -12
  143. src/wallet/spend.cpp +17 -82
  144. src/wallet/spend.h +1 -1
  145. src/wallet/transaction.cpp +4 -0
  146. src/wallet/transaction.h +1 -4
  147. src/wallet/wallet.cpp +327 -166
  148. src/wallet/wallet.h +16 -46
  149. src/wallet/walletdb.h +2 -1
  150. src/warnings.cpp +8 -0
  151. src/warnings.h +1 -0
src/base58.h CHANGED
@@ -1,5 +1,6 @@
1
1
  // Copyright (c) 2009-2010 Satoshi Nakamoto
2
2
  // Copyright (c) 2009-2020 The Bitcoin Core developers
3
+ // Copyright (c) 2011-2023 The Peercoin developers
3
4
  // Distributed under the MIT software license, see the accompanying
4
5
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
6
 
src/bech32.cpp CHANGED
@@ -355,8 +355,8 @@ data CreateChecksum(Encoding encoding, const std::string& hrp, const data& value
355
355
 
356
356
  /** Encode a Bech32 or Bech32m string. */
357
357
  std::string Encode(Encoding encoding, const std::string& hrp, const data& values) {
358
- // First ensure that the HRP is all lowercase. BIP-173 and BIP350 require an encoder
359
- // to return a lowercase Bech32/Bech32m string, but if given an uppercase HRP, the
358
+ // First ensure that the HRP is all lowercase. BIP-173 requires an encoder
359
+ // to return a lowercase Bech32 string, but if given an uppercase HRP, the
360
360
  // result will always be invalid.
361
361
  for (const char& c : hrp) assert(c < 'A' || c > 'Z');
362
362
  data checksum = CreateChecksum(encoding, hrp, values);
src/bech32.h CHANGED
@@ -42,7 +42,7 @@ struct DecodeResult
42
42
  DecodeResult(Encoding enc, std::string&& h, std::vector<uint8_t>&& d) : encoding(enc), hrp(std::move(h)), data(std::move(d)) {}
43
43
  };
44
44
 
45
- /** Decode a Bech32 or Bech32m string. */
45
+ /** Decode a Bech32 string. */
46
46
  DecodeResult Decode(const std::string& str);
47
47
 
48
48
  /** Return the positions of errors in a Bech32 string. */
src/bignum.h ADDED
@@ -0,0 +1,582 @@
1
+ // Copyright (c) 2009-2010 Satoshi Nakamoto
2
+ // Copyright (c) 2009-2012 The Bitcoin developers
3
+ // Copyright (c) 2011-2023 The Peercoin developers
4
+ // Copyright (c) 2018-2018 The Emercoin developers
5
+ #ifndef BITCOIN_BIGNUM_H
6
+ #define BITCOIN_BIGNUM_H
7
+
8
+ #include <stdexcept>
9
+ #include <vector>
10
+ #include <openssl/bn.h>
11
+
12
+ /** Errors thrown by the bignum class */
13
+ class bignum_error : public std::runtime_error
14
+ {
15
+ public:
16
+ explicit bignum_error(const std::string& str) : std::runtime_error(str) {}
17
+ };
18
+
19
+
20
+ /** RAII encapsulated BN_CTX (OpenSSL bignum context) */
21
+ class CAutoBN_CTX
22
+ {
23
+ protected:
24
+ BN_CTX* pctx;
25
+ BN_CTX* operator=(BN_CTX* pnew) { return pctx = pnew; }
26
+
27
+ public:
28
+ CAutoBN_CTX()
29
+ {
30
+ pctx = BN_CTX_new();
31
+ if (pctx == NULL)
32
+ throw bignum_error("CAutoBN_CTX : BN_CTX_new() returned NULL");
33
+ }
34
+
35
+ ~CAutoBN_CTX()
36
+ {
37
+ if (pctx != NULL)
38
+ BN_CTX_free(pctx);
39
+ }
40
+
41
+ operator BN_CTX*() { return pctx; }
42
+ BN_CTX& operator*() { return *pctx; }
43
+ BN_CTX** operator&() { return &pctx; }
44
+ bool operator!() { return (pctx == NULL); }
45
+ };
46
+
47
+
48
+ /** C++ wrapper for BIGNUM (OpenSSL bignum) */
49
+ class CBigNum
50
+ {
51
+ private:
52
+ BIGNUM *self;
53
+
54
+ void init()
55
+ {
56
+ if (self) BN_clear_free(self);
57
+ self = BN_new();
58
+ if (!self)
59
+ throw bignum_error("CBigNum::init() : BN_new() returned NULL");
60
+ }
61
+
62
+ public:
63
+ BIGNUM* get() { return self; }
64
+ const BIGNUM* cget() const { return self; }
65
+
66
+ CBigNum() : self(NULL)
67
+ {
68
+ init();
69
+ }
70
+
71
+ CBigNum(const CBigNum& b) : self(NULL)
72
+ {
73
+ init();
74
+ if (!BN_copy(self, b.cget()))
75
+ {
76
+ BN_clear_free(self);
77
+ throw bignum_error("CBigNum::CBigNum(const CBigNum&) : BN_copy failed");
78
+ }
79
+ }
80
+
81
+ CBigNum& operator=(const CBigNum& b)
82
+ {
83
+ if (!BN_copy(self, b.cget()))
84
+ throw bignum_error("CBigNum::operator= : BN_copy failed");
85
+ return (*this);
86
+ }
87
+
88
+ ~CBigNum()
89
+ {
90
+ if (self) BN_clear_free(self);
91
+ }
92
+
93
+ //CBigNum(char n) is not portable. Use 'signed char' or 'unsigned char'.
94
+ CBigNum(signed char n) : self(NULL) { init(); if (n >= 0) setulong(n); else setint64(n); }
95
+ CBigNum(short n) : self(NULL) { init(); if (n >= 0) setulong(n); else setint64(n); }
96
+ CBigNum(int n) : self(NULL) { init(); if (n >= 0) setulong(n); else setint64(n); }
97
+ CBigNum(int64_t n) : self(NULL) { init(); setint64(n); }
98
+ CBigNum(unsigned char n) : self(NULL) { init(); setulong(n); }
99
+ CBigNum(unsigned short n) : self(NULL) { init(); setulong(n); }
100
+ CBigNum(unsigned int n) : self(NULL) { init(); setulong(n); }
101
+ CBigNum(uint64_t n) : self(NULL) { init(); setuint64(n); }
102
+ explicit CBigNum(uint256 n) : self(NULL) { init(); setuint256(n); }
103
+
104
+ explicit CBigNum(const std::vector<unsigned char>& vch) : self(NULL)
105
+ {
106
+ init();
107
+ setvch(vch);
108
+ }
109
+
110
+ void setulong(unsigned long n)
111
+ {
112
+ if (!BN_set_word(self, n))
113
+ throw bignum_error("CBigNum conversion from unsigned long : BN_set_word failed");
114
+ }
115
+
116
+ unsigned long getulong() const
117
+ {
118
+ return BN_get_word(self);
119
+ }
120
+
121
+ unsigned int getuint() const
122
+ {
123
+ return BN_get_word(self);
124
+ }
125
+
126
+ int getint() const
127
+ {
128
+ unsigned long n = BN_get_word(self);
129
+ if (!BN_is_negative(self))
130
+ return (n > (unsigned long)std::numeric_limits<int>::max() ? std::numeric_limits<int>::max() : n);
131
+ else
132
+ return (n > (unsigned long)std::numeric_limits<int>::max() ? std::numeric_limits<int>::min() : -(int)n);
133
+ }
134
+
135
+ void setint64(int64_t n)
136
+ {
137
+ unsigned char pcx[16], *p = pcx + 15; *p = 0;
138
+ uint8_t neg = 0;
139
+ uint64_t m = n; // to correct care -0
140
+ if(n < 0)
141
+ m = -n, neg = 0x80;
142
+ while(m) {
143
+ *--p = m;
144
+ m >>= 8;
145
+ }
146
+ if((signed char)*p < 0)
147
+ *--p = neg;
148
+ *p |= neg;
149
+ n = pcx + 15 - p;
150
+ *--p = n;
151
+ *--p = 0;
152
+ *--p = 0;
153
+ *--p = 0;
154
+ BN_mpi2bn(p, pcx + 15 - p, self);
155
+ }
156
+
157
+ void setuint64(uint64_t n)
158
+ {
159
+ unsigned char pcx[16], *p = pcx + 15; *p = 0;
160
+ while(n) {
161
+ *--p = n;
162
+ n >>= 8;
163
+ }
164
+ if((signed char)*p < 0)
165
+ *--p = 0;
166
+ n = pcx + 15 - p;
167
+ *--p = n;
168
+ *--p = 0;
169
+ *--p = 0;
170
+ *--p = 0;
171
+ BN_mpi2bn(p, pcx + 15 - p, self);
172
+ }
173
+
174
+ uint64_t getuint64()
175
+ {
176
+ unsigned int nSize = BN_bn2mpi(self, NULL);
177
+ if (nSize < 4)
178
+ return 0;
179
+ std::vector<unsigned char> vch(nSize);
180
+ BN_bn2mpi(self, &vch[0]);
181
+ if (vch.size() > 4)
182
+ vch[4] &= 0x7f;
183
+ uint64_t n = 0;
184
+ for (unsigned int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--)
185
+ ((unsigned char*)&n)[i] = vch[j];
186
+ return n;
187
+ }
188
+
189
+ void setuint256(uint256 n)
190
+ {
191
+ unsigned char pch[sizeof(n) + 6];
192
+ unsigned char* p = pch + 4;
193
+ bool fLeadingZeroes = true;
194
+ unsigned char* pbegin = (unsigned char*)&n;
195
+ unsigned char* psrc = pbegin + sizeof(n);
196
+ while (psrc != pbegin)
197
+ {
198
+ unsigned char c = *(--psrc);
199
+ if (fLeadingZeroes)
200
+ {
201
+ if (c == 0)
202
+ continue;
203
+ if (c & 0x80)
204
+ *p++ = 0;
205
+ fLeadingZeroes = false;
206
+ }
207
+ *p++ = c;
208
+ }
209
+ unsigned int nSize = p - (pch + 4);
210
+ pch[0] = (nSize >> 24) & 0xff;
211
+ pch[1] = (nSize >> 16) & 0xff;
212
+ pch[2] = (nSize >> 8) & 0xff;
213
+ pch[3] = (nSize >> 0) & 0xff;
214
+ BN_mpi2bn(pch, p - pch, self);
215
+ }
216
+
217
+ uint256 getuint256() const
218
+ {
219
+ unsigned int nSize = BN_bn2mpi(self, NULL);
220
+ if (nSize < 4)
221
+ return uint256();
222
+ std::vector<unsigned char> vch(nSize);
223
+ BN_bn2mpi(self, &vch[0]);
224
+ if (vch.size() > 4)
225
+ vch[4] &= 0x7f;
226
+ uint256 n = uint256();
227
+ for (unsigned int i = 0, j = vch.size()-1; i < sizeof(n) && j >= 4; i++, j--)
228
+ ((unsigned char*)&n)[i] = vch[j];
229
+ return n;
230
+ }
231
+
232
+ void setvch(const std::vector<unsigned char>& vch)
233
+ {
234
+ std::vector<unsigned char> vch2(vch.size() + 4);
235
+ unsigned int nSize = vch.size();
236
+ // BIGNUM's byte stream format expects 4 bytes of
237
+ // big endian size data info at the front
238
+ vch2[0] = (nSize >> 24) & 0xff;
239
+ vch2[1] = (nSize >> 16) & 0xff;
240
+ vch2[2] = (nSize >> 8) & 0xff;
241
+ vch2[3] = (nSize >> 0) & 0xff;
242
+ // swap data to big endian
243
+ reverse_copy(vch.begin(), vch.end(), vch2.begin() + 4);
244
+ BN_mpi2bn(&vch2[0], vch2.size(), self);
245
+ }
246
+
247
+ std::vector<unsigned char> getvch() const
248
+ {
249
+ unsigned int nSize = BN_bn2mpi(self, NULL);
250
+ if (nSize <= 4)
251
+ return std::vector<unsigned char>();
252
+ std::vector<unsigned char> vch(nSize);
253
+ BN_bn2mpi(self, &vch[0]);
254
+ vch.erase(vch.begin(), vch.begin() + 4);
255
+ reverse(vch.begin(), vch.end());
256
+ return vch;
257
+ }
258
+
259
+ // The "compact" format is a representation of a whole
260
+ // number N using an unsigned 32bit number similar to a
261
+ // floating point format.
262
+ // The most significant 8 bits are the unsigned exponent of base 256.
263
+ // This exponent can be thought of as "number of bytes of N".
264
+ // The lower 23 bits are the mantissa.
265
+ // Bit number 24 (0x800000) represents the sign of N.
266
+ // N = (-1^sign) * mantissa * 256^(exponent-3)
267
+ //
268
+ // Satoshi's original implementation used BN_bn2mpi() and BN_mpi2bn().
269
+ // MPI uses the most significant bit of the first byte as sign.
270
+ // Thus 0x1234560000 is compact (0x05123456)
271
+ // and 0xc0de000000 is compact (0x0600c0de)
272
+ // (0x05c0de00) would be -0x40de000000
273
+ //
274
+ // Bitcoin only uses this "compact" format for encoding difficulty
275
+ // targets, which are unsigned 256bit quantities. Thus, all the
276
+ // complexities of the sign bit and using base 256 are probably an
277
+ // implementation accident.
278
+ //
279
+ // This implementation directly uses shifts instead of going
280
+ // through an intermediate MPI representation.
281
+ CBigNum& SetCompact(unsigned int nCompact)
282
+ {
283
+ unsigned int nSize = nCompact >> 24;
284
+ bool fNegative =(nCompact & 0x00800000) != 0;
285
+ unsigned int nWord = nCompact & 0x007fffff;
286
+ if (nSize <= 3)
287
+ {
288
+ nWord >>= 8*(3-nSize);
289
+ BN_set_word(self, nWord);
290
+ }
291
+ else
292
+ {
293
+ BN_set_word(self, nWord);
294
+ BN_lshift(self, self, 8*(nSize-3));
295
+ }
296
+ BN_set_negative(self, fNegative);
297
+ return *this;
298
+ }
299
+
300
+ unsigned int GetCompact() const
301
+ {
302
+ unsigned int nSize = BN_num_bytes(self);
303
+ unsigned int nCompact = 0;
304
+ if (nSize <= 3)
305
+ nCompact = BN_get_word(self) << 8*(3-nSize);
306
+ else
307
+ {
308
+ CBigNum bn;
309
+ BN_rshift(bn.get(), self, 8*(nSize-3));
310
+ nCompact = BN_get_word(bn.cget());
311
+ }
312
+ // The 0x00800000 bit denotes the sign.
313
+ // Thus, if it is already set, divide the mantissa by 256 and increase the exponent.
314
+ if (nCompact & 0x00800000)
315
+ {
316
+ nCompact >>= 8;
317
+ nSize++;
318
+ }
319
+ nCompact |= nSize << 24;
320
+ nCompact |= (BN_is_negative(self) ? 0x00800000 : 0);
321
+ return nCompact;
322
+ }
323
+
324
+ void SetHex(const std::string& str)
325
+ {
326
+ // skip 0x
327
+ const char* psz = str.c_str();
328
+ while (isspace(*psz))
329
+ psz++;
330
+ bool fNegative = false;
331
+ if (*psz == '-')
332
+ {
333
+ fNegative = true;
334
+ psz++;
335
+ }
336
+ if (psz[0] == '0' && tolower(psz[1]) == 'x')
337
+ psz += 2;
338
+ while (isspace(*psz))
339
+ psz++;
340
+
341
+ // hex string to bignum
342
+ static const signed char phexdigit[256] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,1,2,3,4,5,6,7,8,9,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, 0,0xa,0xb,0xc,0xd,0xe,0xf,0,0,0,0,0,0,0,0,0 };
343
+ *this = 0;
344
+ while (isxdigit(*psz))
345
+ {
346
+ *this <<= 4;
347
+ int n = phexdigit[(unsigned char)*psz++];
348
+ *this += n;
349
+ }
350
+ if (fNegative)
351
+ *this = 0 - *this;
352
+ }
353
+
354
+ std::string ToString(int nBase=10) const
355
+ {
356
+ CAutoBN_CTX pctx;
357
+ CBigNum bnBase = nBase;
358
+ CBigNum bn0 = 0;
359
+ std::string str;
360
+ CBigNum bn = *this;
361
+ BN_set_negative(bn.get(), false);
362
+ CBigNum dv;
363
+ CBigNum rem;
364
+ if (BN_cmp(bn.get(), bn0.cget()) == 0)
365
+ return "0";
366
+ while (BN_cmp(bn.get(), bn0.cget()) > 0)
367
+ {
368
+ if (!BN_div(dv.get(), rem.get(), bn.cget(), bnBase.cget(), pctx))
369
+ throw bignum_error("CBigNum::ToString() : BN_div failed");
370
+ bn = dv;
371
+ unsigned int c = rem.getulong();
372
+ str += "0123456789abcdef"[c];
373
+ }
374
+ if (BN_is_negative(self))
375
+ str += "-";
376
+ reverse(str.begin(), str.end());
377
+ return str;
378
+ }
379
+
380
+ std::string GetHex() const
381
+ {
382
+ return ToString(16);
383
+ }
384
+
385
+ unsigned int GetSerializeSize(int nType=0, int nVersion=PROTOCOL_VERSION) const
386
+ {
387
+ return ::GetSerializeSize(getvch(), nType, nVersion);
388
+ }
389
+
390
+ template<typename Stream>
391
+ void Serialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION) const
392
+ {
393
+ ::Serialize(s, getvch(), nType, nVersion);
394
+ }
395
+
396
+ template<typename Stream>
397
+ void Unserialize(Stream& s, int nType=0, int nVersion=PROTOCOL_VERSION)
398
+ {
399
+ std::vector<unsigned char> vch;
400
+ ::Unserialize(s, vch, nType, nVersion);
401
+ setvch(vch);
402
+ }
403
+
404
+
405
+ bool operator!() const
406
+ {
407
+ return BN_is_zero(self);
408
+ }
409
+
410
+ CBigNum& operator+=(const CBigNum& b)
411
+ {
412
+ if (!BN_add(self, self, b.cget()))
413
+ throw bignum_error("CBigNum::operator+= : BN_add failed");
414
+ return *this;
415
+ }
416
+
417
+ CBigNum& operator-=(const CBigNum& b)
418
+ {
419
+ *this = *this - b;
420
+ return *this;
421
+ }
422
+
423
+ CBigNum& operator*=(const CBigNum& b)
424
+ {
425
+ CAutoBN_CTX pctx;
426
+ if (!BN_mul(self, self, b.cget(), pctx))
427
+ throw bignum_error("CBigNum::operator*= : BN_mul failed");
428
+ return *this;
429
+ }
430
+
431
+ CBigNum& operator/=(const CBigNum& b)
432
+ {
433
+ *this = *this / b;
434
+ return *this;
435
+ }
436
+
437
+ CBigNum& operator%=(const CBigNum& b)
438
+ {
439
+ *this = *this % b;
440
+ return *this;
441
+ }
442
+
443
+ CBigNum& operator<<=(unsigned int shift)
444
+ {
445
+ if (!BN_lshift(self, self, shift))
446
+ throw bignum_error("CBigNum:operator<<= : BN_lshift failed");
447
+ return *this;
448
+ }
449
+
450
+ CBigNum& operator>>=(unsigned int shift)
451
+ {
452
+ // Note: BN_rshift segfaults on 64-bit if 2^shift is greater than the number
453
+ // if built on ubuntu 9.04 or 9.10, probably depends on version of OpenSSL
454
+ CBigNum a = 1;
455
+ a <<= shift;
456
+ if (BN_cmp(a.cget(), self) > 0)
457
+ {
458
+ *this = 0;
459
+ return *this;
460
+ }
461
+
462
+ if (!BN_rshift(self, self, shift))
463
+ throw bignum_error("CBigNum:operator>>= : BN_rshift failed");
464
+ return *this;
465
+ }
466
+
467
+
468
+ CBigNum& operator++()
469
+ {
470
+ // prefix operator
471
+ if (!BN_add(self, self, BN_value_one()))
472
+ throw bignum_error("CBigNum::operator++ : BN_add failed");
473
+ return *this;
474
+ }
475
+
476
+ const CBigNum operator++(int)
477
+ {
478
+ // postfix operator
479
+ const CBigNum ret = *this;
480
+ ++(*this);
481
+ return ret;
482
+ }
483
+
484
+ CBigNum& operator--()
485
+ {
486
+ // prefix operator
487
+ CBigNum r;
488
+ if (!BN_sub(r.get(), self, BN_value_one()))
489
+ throw bignum_error("CBigNum::operator-- : BN_sub failed");
490
+ *this = r;
491
+ return *this;
492
+ }
493
+
494
+ const CBigNum operator--(int)
495
+ {
496
+ // postfix operator
497
+ const CBigNum ret = *this;
498
+ --(*this);
499
+ return ret;
500
+ }
501
+
502
+
503
+ friend inline const CBigNum operator-(const CBigNum& a, const CBigNum& b);
504
+ friend inline const CBigNum operator/(const CBigNum& a, const CBigNum& b);
505
+ friend inline const CBigNum operator%(const CBigNum& a, const CBigNum& b);
506
+ };
507
+
508
+
509
+
510
+ inline const CBigNum operator+(const CBigNum& a, const CBigNum& b)
511
+ {
512
+ CBigNum r;
513
+ if (!BN_add(r.get(), a.cget(), b.cget()))
514
+ throw bignum_error("CBigNum::operator+ : BN_add failed");
515
+ return r;
516
+ }
517
+
518
+ inline const CBigNum operator-(const CBigNum& a, const CBigNum& b)
519
+ {
520
+ CBigNum r;
521
+ if (!BN_sub(r.get(), a.cget(), b.cget()))
522
+ throw bignum_error("CBigNum::operator- : BN_sub failed");
523
+ return r;
524
+ }
525
+
526
+ inline const CBigNum operator-(const CBigNum& a)
527
+ {
528
+ CBigNum r(a);
529
+ BN_set_negative(r.get(), !BN_is_negative(r.cget()));
530
+ return r;
531
+ }
532
+
533
+ inline const CBigNum operator*(const CBigNum& a, const CBigNum& b)
534
+ {
535
+ CAutoBN_CTX pctx;
536
+ CBigNum r;
537
+ if (!BN_mul(r.get(), a.cget(), b.cget(), pctx))
538
+ throw bignum_error("CBigNum::operator* : BN_mul failed");
539
+ return r;
540
+ }
541
+
542
+ inline const CBigNum operator/(const CBigNum& a, const CBigNum& b)
543
+ {
544
+ CAutoBN_CTX pctx;
545
+ CBigNum r;
546
+ if (!BN_div(r.get(), NULL, a.cget(), b.cget(), pctx))
547
+ throw bignum_error("CBigNum::operator/ : BN_div failed");
548
+ return r;
549
+ }
550
+
551
+ inline const CBigNum operator%(const CBigNum& a, const CBigNum& b)
552
+ {
553
+ CAutoBN_CTX pctx;
554
+ CBigNum r;
555
+ if (!BN_mod(r.get(), a.cget(), b.cget(), pctx))
556
+ throw bignum_error("CBigNum::operator% : BN_div failed");
557
+ return r;
558
+ }
559
+
560
+ inline const CBigNum operator<<(const CBigNum& a, unsigned int shift)
561
+ {
562
+ CBigNum r;
563
+ if (!BN_lshift(r.get(), a.cget(), shift))
564
+ throw bignum_error("CBigNum:operator<< : BN_lshift failed");
565
+ return r;
566
+ }
567
+
568
+ inline const CBigNum operator>>(const CBigNum& a, unsigned int shift)
569
+ {
570
+ CBigNum r = a;
571
+ r >>= shift;
572
+ return r;
573
+ }
574
+
575
+ inline bool operator==(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.cget(), b.cget()) == 0); }
576
+ inline bool operator!=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.cget(), b.cget()) != 0); }
577
+ inline bool operator<=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.cget(), b.cget()) <= 0); }
578
+ inline bool operator>=(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.cget(), b.cget()) >= 0); }
579
+ inline bool operator<(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.cget(), b.cget()) < 0); }
580
+ inline bool operator>(const CBigNum& a, const CBigNum& b) { return (BN_cmp(a.cget(), b.cget()) > 0); }
581
+
582
+ #endif
src/bitcoin-cli.cpp CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  #include <chainparamsbase.h>
11
11
  #include <clientversion.h>
12
- #include <policy/feerate.h>
12
+ #include <consensus/amount.h>
13
13
  #include <rpc/client.h>
14
14
  #include <rpc/mining.h>
15
15
  #include <rpc/protocol.h>
@@ -138,10 +138,10 @@ static int AppInitRPC(int argc, char* argv[])
138
138
  strUsage += FormatParagraph(LicenseInfo());
139
139
  } else {
140
140
  strUsage += "\n"
141
- "Usage: bitcoin-cli [options] <command> [params] Send command to " PACKAGE_NAME "\n"
142
- "or: bitcoin-cli [options] -named <command> [name=value]... Send command to " PACKAGE_NAME " (with named arguments)\n"
143
- "or: bitcoin-cli [options] help List commands\n"
144
- "or: bitcoin-cli [options] help <command> Get help for a command\n";
141
+ "Usage: peercoin-cli [options] <command> [params] Send command to " PACKAGE_NAME "\n"
142
+ "or: peercoin-cli [options] -named <command> [name=value]... Send command to " PACKAGE_NAME " (with named arguments)\n"
143
+ "or: peercoin-cli [options] help List commands\n"
144
+ "or: peercoin-cli [options] help <command> Get help for a command\n";
145
145
  strUsage += "\n" + gArgs.GetHelpMessage();
146
146
  }
147
147
 
@@ -800,7 +800,7 @@ static UniValue CallRPC(BaseRequestHandler* rh, const std::string& strMethod, co
800
800
  if (response.error != -1) {
801
801
  responseErrorMessage = strprintf(" (error code %d - \"%s\")", response.error, http_errorstring(response.error));
802
802
  }
803
- throw CConnectionFailed(strprintf("Could not connect to the server %s:%d%s\n\nMake sure the bitcoind server is running and that you are connecting to the correct RPC port.", host, port, responseErrorMessage));
803
+ throw CConnectionFailed(strprintf("Could not connect to the server %s:%d%s\n\nMake sure the peercoind server is running and that you are connecting to the correct RPC port.", host, port, responseErrorMessage));
804
804
  } else if (response.status == HTTP_UNAUTHORIZED) {
805
805
  if (failedToGetAuthCookie) {
806
806
  throw std::runtime_error(strprintf(
src/bitcoin-tx.cpp CHANGED
@@ -14,14 +14,12 @@
14
14
  #include <key_io.h>
15
15
  #include <fs.h>
16
16
  #include <policy/policy.h>
17
- #include <policy/rbf.h>
18
17
  #include <primitives/transaction.h>
19
18
  #include <script/script.h>
20
19
  #include <script/sign.h>
21
20
  #include <script/signingprovider.h>
22
21
  #include <univalue.h>
23
22
  #include <util/moneystr.h>
24
- #include <util/rbf.h>
25
23
  #include <util/strencodings.h>
26
24
  #include <util/string.h>
27
25
  #include <util/system.h>
@@ -54,6 +52,7 @@ static void SetupBitcoinTxArgs(ArgsManager &argsman)
54
52
  argsman.AddArg("in=TXID:VOUT(:SEQUENCE_NUMBER)", "Add input to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
55
53
  argsman.AddArg("locktime=N", "Set TX lock time to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
56
54
  argsman.AddArg("nversion=N", "Set TX version to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
55
+ argsman.AddArg("ntime=N", "Set TX timestamp to N", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
57
56
  argsman.AddArg("outaddr=VALUE:ADDRESS", "Add address-based output to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
58
57
  argsman.AddArg("outdata=[VALUE:]DATA", "Add data-based output to TX", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
59
58
  argsman.AddArg("outmultisig=VALUE:REQUIRED:PUBKEYS:PUBKEY1:PUBKEY2:....[:FLAGS]", "Add Pay To n-of-m Multi-sig output to TX. n = REQUIRED, m = PUBKEYS. "
@@ -65,7 +64,6 @@ static void SetupBitcoinTxArgs(ArgsManager &argsman)
65
64
  argsman.AddArg("outscript=VALUE:SCRIPT[:FLAGS]", "Add raw script output to TX. "
66
65
  "Optionally add the \"W\" flag to produce a pay-to-witness-script-hash output. "
67
66
  "Optionally add the \"S\" flag to wrap the output in a pay-to-script-hash.", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
68
- argsman.AddArg("replaceable(=N)", "Set RBF opt-in sequence number for input N (if not provided, opt-in all available inputs)", ArgsManager::ALLOW_ANY, OptionsCategory::COMMANDS);
69
67
  argsman.AddArg("sign=SIGHASH-FLAGS", "Add zero or more signatures to transaction. "
70
68
  "This command requires JSON registers:"
71
69
  "prevtxs=JSON object, "
@@ -101,14 +99,14 @@ static int AppInitRawTx(int argc, char* argv[])
101
99
 
102
100
  if (argc < 2 || HelpRequested(gArgs) || gArgs.IsArgSet("-version")) {
103
101
  // First part of help message is specific to this utility
104
- std::string strUsage = PACKAGE_NAME " bitcoin-tx utility version " + FormatFullVersion() + "\n";
102
+ std::string strUsage = PACKAGE_NAME " peercoin-tx utility version " + FormatFullVersion() + "\n";
105
103
 
106
104
  if (gArgs.IsArgSet("-version")) {
107
105
  strUsage += FormatParagraph(LicenseInfo());
108
106
  } else {
109
107
  strUsage += "\n"
110
- "Usage: bitcoin-tx [options] <hex-tx> [commands] Update hex-encoded bitcoin transaction\n"
111
- "or: bitcoin-tx [options] -create [commands] Create hex-encoded bitcoin transaction\n"
108
+ "Usage: peercoin-tx [options] <hex-tx> [commands] Update hex-encoded peercoin transaction\n"
109
+ "or: peercoin-tx [options] -create [commands] Create hex-encoded peercoin transaction\n"
112
110
  "\n";
113
111
  strUsage += gArgs.GetHelpMessage();
114
112
  }
@@ -219,24 +217,13 @@ static void MutateTxLocktime(CMutableTransaction& tx, const std::string& cmdVal)
219
217
  tx.nLockTime = (unsigned int) newLocktime;
220
218
  }
221
219
 
222
- static void MutateTxRBFOptIn(CMutableTransaction& tx, const std::string& strInIdx)
220
+ static void MutateTxTime(CMutableTransaction& tx, const std::string& cmdVal)
223
221
  {
224
- // parse requested index
225
- int64_t inIdx;
226
- if (!ParseInt64(strInIdx, &inIdx) || inIdx < 0 || inIdx >= static_cast<int64_t>(tx.vin.size())) {
227
- throw std::runtime_error("Invalid TX input index '" + strInIdx + "'");
228
- }
222
+ int64_t newTime;
223
+ if (!ParseInt64(cmdVal, &newTime) || newTime < 0LL || newTime > 0xffffffffLL)
224
+ throw std::runtime_error("Invalid TX time requested: '" + cmdVal + "'");
229
225
 
230
- // set the nSequence to MAX_INT - 2 (= RBF opt in flag)
231
- int cnt = 0;
232
- for (CTxIn& txin : tx.vin) {
233
- if (strInIdx == "" || cnt == inIdx) {
234
- if (txin.nSequence > MAX_BIP125_RBF_SEQUENCE) {
235
- txin.nSequence = MAX_BIP125_RBF_SEQUENCE;
236
- }
237
- }
238
- ++cnt;
239
- }
226
+ tx.nTime = (unsigned int) newTime;
240
227
  }
241
228
 
242
229
  template <typename T>
@@ -559,7 +546,7 @@ static CAmount AmountFromValue(const UniValue& value)
559
546
  if (!value.isNum() && !value.isStr())
560
547
  throw std::runtime_error("Amount is not a number or string");
561
548
  CAmount amount;
562
- if (!ParseFixedPoint(value.getValStr(), 8, &amount))
549
+ if (!ParseFixedPoint(value.getValStr(), 6, &amount))
563
550
  throw std::runtime_error("Invalid amount");
564
551
  if (!MoneyRange(amount))
565
552
  throw std::runtime_error("Amount out of range");
@@ -708,9 +695,8 @@ static void MutateTx(CMutableTransaction& tx, const std::string& command,
708
695
  MutateTxVersion(tx, commandVal);
709
696
  else if (command == "locktime")
710
697
  MutateTxLocktime(tx, commandVal);
711
- else if (command == "replaceable") {
712
- MutateTxRBFOptIn(tx, commandVal);
713
- }
698
+ else if (command == "ntime")
699
+ MutateTxTime(tx, commandVal);
714
700
 
715
701
  else if (command == "delin")
716
702
  MutateTxDelInput(tx, commandVal);
src/bitcoind.cpp CHANGED
@@ -114,7 +114,7 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
114
114
 
115
115
  util::ThreadSetInternalName("init");
116
116
 
117
- // If Qt is used, parameters/bitcoin.conf are parsed in qt/bitcoin.cpp's main()
117
+ // If Qt is used, parameters/peercoin.conf are parsed in qt/bitcoin.cpp's main()
118
118
  ArgsManager& args = *Assert(node.args);
119
119
  SetupServerArgs(args);
120
120
  std::string error;
@@ -129,7 +129,7 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
129
129
  if (args.IsArgSet("-version")) {
130
130
  strUsage += FormatParagraph(LicenseInfo());
131
131
  } else {
132
- strUsage += "\nUsage: bitcoind [options] Start " PACKAGE_NAME "\n"
132
+ strUsage += "\nUsage: peercoind [options] Start " PACKAGE_NAME "\n"
133
133
  "\n";
134
134
  strUsage += args.GetHelpMessage();
135
135
  }
@@ -165,7 +165,7 @@ static bool AppInit(NodeContext& node, int argc, char* argv[])
165
165
  // Error out when loose non-argument tokens are encountered on command line
166
166
  for (int i = 1; i < argc; i++) {
167
167
  if (!IsSwitchChar(argv[i][0])) {
168
- return InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see bitcoind -h for a list of options.\n", argv[i])));
168
+ return InitError(Untranslated(strprintf("Command line contains unexpected token '%s', see peercoind -h for a list of options.\n", argv[i])));
169
169
  }
170
170
  }
171
171
 
src/blockencodings.cpp CHANGED
@@ -18,10 +18,11 @@
18
18
 
19
19
  CBlockHeaderAndShortTxIDs::CBlockHeaderAndShortTxIDs(const CBlock& block, bool fUseWTXID) :
20
20
  nonce(GetRand(std::numeric_limits<uint64_t>::max())),
21
- shorttxids(block.vtx.size() - 1), prefilledtxn(1), header(block) {
21
+ shorttxids(block.vtx.size() - 1), prefilledtxn(1), header(block), vchBlockSig(block.vchBlockSig) {
22
22
  FillShortTxIDSelector();
23
23
  //TODO: Use our mempool prior to block acceptance to predictively fill more than just the coinbase
24
24
  prefilledtxn[0] = {0, block.vtx[0]};
25
+ header.nFlags = block.nFlags;
25
26
  for (size_t i = 1; i < block.vtx.size(); i++) {
26
27
  const CTransaction& tx = *block.vtx[i];
27
28
  shorttxids[i - 1] = GetShortID(fUseWTXID ? tx.GetWitnessHash() : tx.GetHash());
@@ -54,6 +55,7 @@ ReadStatus PartiallyDownloadedBlock::InitData(const CBlockHeaderAndShortTxIDs& c
54
55
 
55
56
  assert(header.IsNull() && txn_available.empty());
56
57
  header = cmpctblock.header;
58
+ vchBlockSig = cmpctblock.vchBlockSig;
57
59
  txn_available.resize(cmpctblock.BlockTxCount());
58
60
 
59
61
  int32_t lastprefilledindex = -1;
@@ -177,6 +179,7 @@ ReadStatus PartiallyDownloadedBlock::FillBlock(CBlock& block, const std::vector<
177
179
  assert(!header.IsNull());
178
180
  uint256 hash = header.GetHash();
179
181
  block = header;
182
+ block.vchBlockSig = vchBlockSig;
180
183
  block.vtx.resize(txn_available.size());
181
184
 
182
185
  size_t tx_missing_offset = 0;
src/blockencodings.h CHANGED
@@ -100,6 +100,7 @@ public:
100
100
  static constexpr int SHORTTXIDS_LENGTH = 6;
101
101
 
102
102
  CBlockHeader header;
103
+ std::vector<unsigned char> vchBlockSig;
103
104
 
104
105
  // Dummy for deserialization
105
106
  CBlockHeaderAndShortTxIDs() {}
@@ -112,7 +113,7 @@ public:
112
113
 
113
114
  SERIALIZE_METHODS(CBlockHeaderAndShortTxIDs, obj)
114
115
  {
115
- READWRITE(obj.header, obj.nonce, Using<VectorFormatter<CustomUintFormatter<SHORTTXIDS_LENGTH>>>(obj.shorttxids), obj.prefilledtxn);
116
+ READWRITE(obj.header, obj.nonce, obj.vchBlockSig, Using<VectorFormatter<CustomUintFormatter<SHORTTXIDS_LENGTH>>>(obj.shorttxids), obj.prefilledtxn);
116
117
  if (ser_action.ForRead()) {
117
118
  if (obj.BlockTxCount() > std::numeric_limits<uint16_t>::max()) {
118
119
  throw std::ios_base::failure("indexes overflowed 16 bits");
@@ -129,6 +130,7 @@ protected:
129
130
  const CTxMemPool* pool;
130
131
  public:
131
132
  CBlockHeader header;
133
+ std::vector<unsigned char> vchBlockSig;
132
134
  explicit PartiallyDownloadedBlock(CTxMemPool* poolIn) : pool(poolIn) {}
133
135
 
134
136
  // extra_txn is a list of extra transactions to look at, in <witness hash, reference> form
src/chain.cpp CHANGED
@@ -122,7 +122,7 @@ void CBlockIndex::BuildSkip()
122
122
  pskip = pprev->GetAncestor(GetSkipHeight(nHeight));
123
123
  }
124
124
 
125
- arith_uint256 GetBlockProof(const CBlockIndex& block)
125
+ arith_uint256 GetBlockTrust(const CBlockIndex& block)
126
126
  {
127
127
  arith_uint256 bnTarget;
128
128
  bool fNegative;
@@ -134,20 +134,20 @@ arith_uint256 GetBlockProof(const CBlockIndex& block)
134
134
  // as it's too large for an arith_uint256. However, as 2**256 is at least as large
135
135
  // as bnTarget+1, it is equal to ((2**256 - bnTarget - 1) / (bnTarget+1)) + 1,
136
136
  // or ~bnTarget / (bnTarget+1) + 1.
137
- return (~bnTarget / (bnTarget + 1)) + 1;
137
+ return block.IsProofOfStake() ? (~bnTarget / (bnTarget + 1)) + 1 : 1;
138
138
  }
139
139
 
140
140
  int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params& params)
141
141
  {
142
142
  arith_uint256 r;
143
143
  int sign = 1;
144
- if (to.nChainWork > from.nChainWork) {
145
- r = to.nChainWork - from.nChainWork;
144
+ if (to.nChainTrust > from.nChainTrust) {
145
+ r = to.nChainTrust - from.nChainTrust;
146
146
  } else {
147
- r = from.nChainWork - to.nChainWork;
147
+ r = from.nChainTrust - to.nChainTrust;
148
148
  sign = -1;
149
149
  }
150
- r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockProof(tip);
150
+ r = r * arith_uint256(params.nPowTargetSpacing) / GetBlockTrust(tip);
151
151
  if (r.bits() > 63) {
152
152
  return sign * std::numeric_limits<int64_t>::max();
153
153
  }
@@ -172,3 +172,11 @@ const CBlockIndex* LastCommonAncestor(const CBlockIndex* pa, const CBlockIndex*
172
172
  assert(pa == pb);
173
173
  return pa;
174
174
  }
175
+
176
+ // peercoin: find last block index up to pindex
177
+ const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake)
178
+ {
179
+ while (pindex && pindex->pprev && (pindex->IsProofOfStake() != fProofOfStake))
180
+ pindex = pindex->pprev;
181
+ return pindex;
182
+ }
src/chain.h CHANGED
@@ -14,13 +14,16 @@
14
14
  #include <tinyformat.h>
15
15
  #include <uint256.h>
16
16
 
17
+ #include <util/moneystr.h>
18
+
17
19
  #include <vector>
18
20
 
19
21
  /**
20
22
  * Maximum amount of time that a block timestamp is allowed to exceed the
21
23
  * current network-adjusted time before the block will be accepted.
22
24
  */
23
- static constexpr int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60;
25
+ static constexpr int64_t MAX_FUTURE_BLOCK_TIME_PREV9 = 2 * 60 * 60;
26
+ static constexpr int64_t MAX_FUTURE_BLOCK_TIME = 15 * 60;
24
27
 
25
28
  /**
26
29
  * Timestamp window used as a grace period by code that compares external
@@ -28,7 +31,7 @@ static constexpr int64_t MAX_FUTURE_BLOCK_TIME = 2 * 60 * 60;
28
31
  * to block timestamps. This should be set at least as high as
29
32
  * MAX_FUTURE_BLOCK_TIME.
30
33
  */
31
- static constexpr int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME;
34
+ static constexpr int64_t TIMESTAMP_WINDOW = MAX_FUTURE_BLOCK_TIME_PREV9;
32
35
 
33
36
  /**
34
37
  * Maximum gap between node time and block time used
@@ -173,7 +176,7 @@ public:
173
176
  unsigned int nUndoPos GUARDED_BY(::cs_main){0};
174
177
 
175
178
  //! (memory only) Total amount of work (expected number of hashes) in the chain up to and including this block
176
- arith_uint256 nChainWork{};
179
+ arith_uint256 nChainTrust{};
177
180
 
178
181
  //! Number of transactions in this block.
179
182
  //! Note: in a potential headers-first mode, this number cannot be relied upon
@@ -213,6 +216,66 @@ public:
213
216
  //! (memory only) Maximum nTime in the chain up to and including this block.
214
217
  unsigned int nTimeMax{0};
215
218
 
219
+ // peercoin
220
+ // peercoin: money supply related block index fields
221
+ int64_t nMint{0};
222
+ int64_t nMoneySupply{0};
223
+
224
+ // peercoin: proof-of-stake related block index fields
225
+ unsigned int nFlags{0}; // peercoin: block index flags
226
+ enum
227
+ {
228
+ BLOCK_PROOF_OF_STAKE = (1 << 0), // is proof-of-stake block
229
+ BLOCK_STAKE_ENTROPY = (1 << 1), // entropy bit for stake modifier
230
+ BLOCK_STAKE_MODIFIER = (1 << 2), // regenerated stake modifier
231
+ };
232
+ uint64_t nStakeModifier{0}; // hash modifier for proof-of-stake
233
+ unsigned int nStakeModifierChecksum{0}; // checksum of index; in-memeory only
234
+ COutPoint prevoutStake{};
235
+ unsigned int nStakeTime{0};
236
+ uint256 hashProofOfStake{};
237
+
238
+ bool IsProofOfWork() const
239
+ {
240
+ return !(nFlags & BLOCK_PROOF_OF_STAKE);
241
+ }
242
+
243
+ bool IsProofOfStake() const
244
+ {
245
+ return (nFlags & BLOCK_PROOF_OF_STAKE);
246
+ }
247
+
248
+ void SetProofOfStake()
249
+ {
250
+ nFlags |= BLOCK_PROOF_OF_STAKE;
251
+ }
252
+
253
+ unsigned int GetStakeEntropyBit() const
254
+ {
255
+ return ((nFlags & BLOCK_STAKE_ENTROPY) >> 1);
256
+ }
257
+
258
+ bool SetStakeEntropyBit(unsigned int nEntropyBit)
259
+ {
260
+ if (nEntropyBit > 1)
261
+ return false;
262
+ nFlags |= (nEntropyBit? BLOCK_STAKE_ENTROPY : 0);
263
+ return true;
264
+ }
265
+
266
+ bool GeneratedStakeModifier() const
267
+ {
268
+ return (nFlags & BLOCK_STAKE_MODIFIER);
269
+ }
270
+
271
+ void SetStakeModifier(uint64_t nModifier, bool fGeneratedStakeModifier)
272
+ {
273
+ nStakeModifier = nModifier;
274
+ if (fGeneratedStakeModifier)
275
+ nFlags |= BLOCK_STAKE_MODIFIER;
276
+ }
277
+ // peercoin end
278
+
216
279
  CBlockIndex()
217
280
  {
218
281
  }
@@ -222,7 +285,8 @@ public:
222
285
  hashMerkleRoot{block.hashMerkleRoot},
223
286
  nTime{block.nTime},
224
287
  nBits{block.nBits},
225
- nNonce{block.nNonce}
288
+ nNonce{block.nNonce},
289
+ nFlags{block.nFlags}
226
290
  {
227
291
  }
228
292
 
@@ -258,6 +322,7 @@ public:
258
322
  block.nTime = nTime;
259
323
  block.nBits = nBits;
260
324
  block.nNonce = nNonce;
325
+ block.nFlags = nFlags;
261
326
  return block;
262
327
  }
263
328
 
@@ -271,7 +336,7 @@ public:
271
336
  * downloaded (and stored to disk) at some point.
272
337
  *
273
338
  * Does not imply the transactions are consensus-valid (ConnectTip might fail)
274
- * Does not imply the transactions are still stored on disk. (IsBlockPruned might return true)
339
+ * Does not imply the transactions are still stored on disk.
275
340
  */
276
341
  bool HaveTxsDownloaded() const { return nChainTx != 0; }
277
342
 
@@ -285,6 +350,32 @@ public:
285
350
  return (int64_t)nTimeMax;
286
351
  }
287
352
 
353
+ /**
354
+ * Duplicate from bitcoinrpc that originaly define this method.
355
+ * May require some cleanup since this method should be available both for rpc
356
+ * and qt clients.
357
+ */
358
+ double GetBlockDifficulty() const
359
+ {
360
+ int nShift = (nBits >> 24) & 0xff;
361
+
362
+ double dDiff =
363
+ (double)0x0000ffff / (double)(nBits & 0x00ffffff);
364
+
365
+ while (nShift < 29)
366
+ {
367
+ dDiff *= 256.0;
368
+ nShift++;
369
+ }
370
+ while (nShift > 29)
371
+ {
372
+ dDiff /= 256.0;
373
+ nShift--;
374
+ }
375
+
376
+ return dDiff;
377
+ }
378
+
288
379
  static constexpr int nMedianTimeSpan = 11;
289
380
 
290
381
  int64_t GetMedianTimePast() const
@@ -303,10 +394,15 @@ public:
303
394
 
304
395
  std::string ToString() const
305
396
  {
306
- return strprintf("CBlockIndex(pprev=%p, nHeight=%d, merkle=%s, hashBlock=%s)",
307
- pprev, nHeight,
308
- hashMerkleRoot.ToString(),
309
- GetBlockHash().ToString());
397
+ return strprintf("CBlockIndex(nprev=%08x, nFile=%d, nHeight=%d, nMint=%s, nMoneySupply=%s, nFlags=(%s)(%d)(%s), nStakeModifier=%016llx, nStakeModifierChecksum=%08x, hashProofOfStake=%s, prevoutStake=(%s), nStakeTime=%d merkle=%s, hashBlock=%s)",
398
+ pprev, nFile, nHeight,
399
+ FormatMoney(nMint), FormatMoney(nMoneySupply),
400
+ GeneratedStakeModifier() ? "MOD" : "-", GetStakeEntropyBit(), IsProofOfStake()? "PoS" : "PoW",
401
+ nStakeModifier, nStakeModifierChecksum,
402
+ hashProofOfStake.ToString(),
403
+ prevoutStake.ToString(), nStakeTime,
404
+ hashMerkleRoot.ToString().substr(0,10),
405
+ GetBlockHash().ToString().substr(0,20));
310
406
  }
311
407
 
312
408
  //! Check whether this block index entry is valid up to the passed validity level.
@@ -357,7 +453,7 @@ public:
357
453
  const CBlockIndex* GetAncestor(int height) const;
358
454
  };
359
455
 
360
- arith_uint256 GetBlockProof(const CBlockIndex& block);
456
+ arith_uint256 GetBlockTrust(const CBlockIndex& block);
361
457
  /** Return the time it would take to redo the work difference between from and to, assuming the current hashrate corresponds to the difficulty at tip, in seconds. */
362
458
  int64_t GetBlockProofEquivalentTime(const CBlockIndex& to, const CBlockIndex& from, const CBlockIndex& tip, const Consensus::Params&);
363
459
  /** Find the forking point between two chain tips. */
@@ -393,6 +489,17 @@ public:
393
489
  if (obj.nStatus & BLOCK_HAVE_DATA) READWRITE(VARINT(obj.nDataPos));
394
490
  if (obj.nStatus & BLOCK_HAVE_UNDO) READWRITE(VARINT(obj.nUndoPos));
395
491
 
492
+ READWRITE(obj.nMint);
493
+ READWRITE(obj.nMoneySupply);
494
+ READWRITE(obj.nFlags);
495
+ READWRITE(obj.nStakeModifier);
496
+ if (obj.nFlags & BLOCK_PROOF_OF_STAKE)
497
+ {
498
+ READWRITE(obj.prevoutStake);
499
+ READWRITE(obj.nStakeTime);
500
+ READWRITE(obj.hashProofOfStake);
501
+ }
502
+
396
503
  // block header
397
504
  READWRITE(obj.nVersion);
398
505
  READWRITE(obj.hashPrev);
@@ -491,4 +598,6 @@ public:
491
598
  CBlockIndex* FindEarliestAtLeast(int64_t nTime, int height) const;
492
599
  };
493
600
 
601
+ const CBlockIndex* GetLastBlockIndex(const CBlockIndex* pindex, bool fProofOfStake);
602
+
494
603
  #endif // BITCOIN_CHAIN_H
src/chainparams.cpp CHANGED
@@ -16,18 +16,19 @@
16
16
  #include <boost/algorithm/string/classification.hpp>
17
17
  #include <boost/algorithm/string/split.hpp>
18
18
 
19
- static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
19
+ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesisOutputScript, uint32_t nTimeTx, uint32_t nTimeBlock, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
20
20
  {
21
21
  CMutableTransaction txNew;
22
22
  txNew.nVersion = 1;
23
23
  txNew.vin.resize(1);
24
24
  txNew.vout.resize(1);
25
- txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(4) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
25
+ txNew.vin[0].scriptSig = CScript() << 486604799 << CScriptNum(9999) << std::vector<unsigned char>((const unsigned char*)pszTimestamp, (const unsigned char*)pszTimestamp + strlen(pszTimestamp));
26
26
  txNew.vout[0].nValue = genesisReward;
27
27
  txNew.vout[0].scriptPubKey = genesisOutputScript;
28
+ txNew.nTime = nTimeTx;
28
29
 
29
30
  CBlock genesis;
30
- genesis.nTime = nTime;
31
+ genesis.nTime = nTimeBlock;
31
32
  genesis.nBits = nBits;
32
33
  genesis.nNonce = nNonce;
33
34
  genesis.nVersion = nVersion;
@@ -48,11 +49,11 @@ static CBlock CreateGenesisBlock(const char* pszTimestamp, const CScript& genesi
48
49
  * CTxOut(nValue=50.00000000, scriptPubKey=0x5F1DF16B2B704C8A578D0B)
49
50
  * vMerkleTree: 4a5e1e
50
51
  */
51
- static CBlock CreateGenesisBlock(uint32_t nTime, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
52
+ static CBlock CreateGenesisBlock(uint32_t nTimeTx, uint32_t nTimeBlock, uint32_t nNonce, uint32_t nBits, int32_t nVersion, const CAmount& genesisReward)
52
53
  {
53
- const char* pszTimestamp = "The Times 03/Jan/2009 Chancellor on brink of second bailout for banks";
54
- const CScript genesisOutputScript = CScript() << ParseHex("04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f") << OP_CHECKSIG;
55
- return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTime, nNonce, nBits, nVersion, genesisReward);
54
+ const char* pszTimestamp = "Matonis 07-AUG-2012 Parallel Currencies And The Roadmap To Monetary Freedom";
55
+ const CScript genesisOutputScript = CScript();
56
+ return CreateGenesisBlock(pszTimestamp, genesisOutputScript, nTimeTx, nTimeBlock, nNonce, nBits, nVersion, genesisReward);
56
57
  }
57
58
 
58
59
  /**
@@ -64,80 +65,71 @@ public:
64
65
  strNetworkID = CBaseChainParams::MAIN;
65
66
  consensus.signet_blocks = false;
66
67
  consensus.signet_challenge.clear();
67
- consensus.nSubsidyHalvingInterval = 210000;
68
- consensus.BIP16Exception = uint256S("0x00000000000002dc756eebf4f49723ed8d30cc28a5f108eb94b1ba88ac4f9c22");
69
- consensus.BIP34Height = 227931;
70
- consensus.BIP34Hash = uint256S("0x000000000000024b89b42a942fe0d9fea3bb44ab7bd1b19115dd6a759c0808b8");
71
- consensus.BIP65Height = 388381; // 000000000000000004c2b624ed5d7756c508d90fd0da2c7c679febfa6c4735f0
72
- consensus.BIP66Height = 363725; // 00000000000000000379eaa19dce8c9b722d46ae6a57c2f1a988119488b50931
73
- consensus.CSVHeight = 419328; // 000000000000000004a1b34462cb8aeebd5799177f7a29cf28f2d1961716b5b5
74
- consensus.SegwitHeight = 481824; // 0000000000000000001c8018d9cb3b742ef25114f27563e3fc4a1902167f9893
75
- consensus.MinBIP9WarningHeight = 483840; // segwit activation height + miner confirmation window
76
- consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
77
- consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
78
- consensus.nPowTargetSpacing = 10 * 60;
68
+ //consensus.BIP16Height = 0;
69
+ consensus.BIP34Height = 339994;
70
+ consensus.BIP34Hash = uint256S("000000000000000237f50af4cfe8924e8693abc5bd8ae5abb95bc6d230f5953f");
71
+ consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~arith_uint256(0) >> 32;
72
+ consensus.bnInitialHashTarget = uint256S("0000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~arith_uint256(0) >> 40;
73
+
74
+ consensus.nTargetTimespan = 7 * 24 * 60 * 60; // one week
75
+ consensus.nStakeTargetSpacing = 10 * 60; // 10-minute block spacing
76
+ consensus.nTargetSpacingWorkMax = 12 * consensus.nStakeTargetSpacing; // 2-hour
77
+ consensus.nPowTargetSpacing = consensus.nStakeTargetSpacing;
78
+ consensus.nStakeMinAge = 60 * 60 * 24 * 30; // minimum age for coin age
79
+ consensus.nStakeMaxAge = 60 * 60 * 24 * 90;
80
+ consensus.nModifierInterval = 6 * 60 * 60; // Modifier interval: time to elapse before new modifier is computed
81
+ consensus.nCoinbaseMaturity = 500;
82
+
79
83
  consensus.fPowAllowMinDifficultyBlocks = false;
80
84
  consensus.fPowNoRetargeting = false;
81
85
  consensus.nRuleChangeActivationThreshold = 1815; // 90% of 2016
82
86
  consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
83
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
84
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
85
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
86
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
87
87
 
88
- // Deployment of Taproot (BIPs 340-342)
89
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
90
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1619222400; // April 24th, 2021
91
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021
92
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 709632; // Approximately November 12th, 2021
88
+ consensus.SegwitHeight = 455470;
93
89
 
94
- consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000002927cdceccbd5209e81e80db");
95
- consensus.defaultAssumeValid = uint256S("0x000000000000000000052d314a259755ca65944e68df6b12a067ea8f1f5a7091"); // 724466
90
+ consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000002a0fac8b39f476"); // 350000
91
+ consensus.defaultAssumeValid = uint256S("0xa3a0ffa0dbca75923ad6a53d3878d62f8b35c363282df3f13ded9e4fda921e63"); // 380000
96
92
 
97
93
  /**
98
94
  * The message start string is designed to be unlikely to occur in normal data.
99
95
  * The characters are rarely used upper ASCII, not valid as UTF-8, and produce
100
96
  * a large 32-bit integer with any alignment.
101
97
  */
102
- pchMessageStart[0] = 0xf9;
103
- pchMessageStart[1] = 0xbe;
104
- pchMessageStart[2] = 0xb4;
105
- pchMessageStart[3] = 0xd9;
106
- nDefaultPort = 8333;
98
+ pchMessageStart[0] = 0xe6;
99
+ pchMessageStart[1] = 0xe8;
100
+ pchMessageStart[2] = 0xe9;
101
+ pchMessageStart[3] = 0xe5;
102
+ nDefaultPort = 9901;
107
103
  nPruneAfterHeight = 100000;
108
- m_assumed_blockchain_size = 460;
109
- m_assumed_chain_state_size = 6;
104
+ m_assumed_blockchain_size = 1;
110
105
 
111
- genesis = CreateGenesisBlock(1231006505, 2083236893, 0x1d00ffff, 1, 50 * COIN);
106
+ genesis = CreateGenesisBlock(1345083810, 1345084287, 2179302059u, 0x1d00ffff, 1, 0);
112
107
  consensus.hashGenesisBlock = genesis.GetHash();
113
- assert(consensus.hashGenesisBlock == uint256S("0x000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"));
114
- assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
108
+ assert(consensus.hashGenesisBlock == uint256S("0x0000000032fe677166d54963b62a4677d8957e87c508eaa4fd7eb1c880cd27e3"));
109
+ assert(genesis.hashMerkleRoot == uint256S("0x3c2d8f85fab4d17aac558cc648a1a58acff0de6deb890c29985690052c5993c2"));
115
110
 
116
111
  // Note that of those which support the service bits prefix, most only support a subset of
117
112
  // possible options.
118
113
  // This is fine at runtime as we'll fall back to using them as an addrfetch if they don't support the
119
114
  // service bits we want, but we should get them updated to support all service bits wanted by any
120
115
  // release ASAP to avoid it where possible.
121
- vSeeds.emplace_back("seed.bitcoin.sipa.be."); // Pieter Wuille, only supports x1, x5, x9, and xd
122
- vSeeds.emplace_back("dnsseed.bluematt.me."); // Matt Corallo, only supports x9
123
- vSeeds.emplace_back("dnsseed.bitcoin.dashjr.org."); // Luke Dashjr
124
- vSeeds.emplace_back("seed.bitcoinstats.com."); // Christian Decker, supports x1 - xf
125
- vSeeds.emplace_back("seed.bitcoin.jonasschnelli.ch."); // Jonas Schnelli, only supports x1, x5, x9, and xd
126
- vSeeds.emplace_back("seed.btc.petertodd.org."); // Peter Todd, only supports x1, x5, x9, and xd
127
- vSeeds.emplace_back("seed.bitcoin.sprovoost.nl."); // Sjors Provoost
128
- vSeeds.emplace_back("dnsseed.emzy.de."); // Stephan Oeste
129
- vSeeds.emplace_back("seed.bitcoin.wiz.biz."); // Jason Maurice
130
-
131
- base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,0);
132
- base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,5);
133
- base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,128);
116
+ vSeeds.emplace_back("seed.peercoin.net");
117
+ vSeeds.emplace_back("seed2.peercoin.net");
118
+ vSeeds.emplace_back("seed.peercoin-library.org");
119
+ vSeeds.emplace_back("seed.ppcoin.info");
120
+
121
+ base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,55); // peercoin: addresses begin with 'P'
122
+ base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,117); // peercoin: addresses begin with 'p'
123
+ base58Prefixes[SECRET_KEY] = std::vector<unsigned char>(1,183);
134
124
  base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x88, 0xB2, 0x1E};
135
125
  base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x88, 0xAD, 0xE4};
136
126
 
137
- bech32_hrp = "bc";
127
+ // human readable prefix to bench32 address
128
+ bech32_hrp = "pc";
138
129
 
139
130
  vFixedSeeds = std::vector<uint8_t>(std::begin(chainparams_seed_main), std::end(chainparams_seed_main));
140
131
 
132
+ fMiningRequiresPeers = true;
141
133
  fDefaultConsistencyChecks = false;
142
134
  fRequireStandard = true;
143
135
  m_is_test_chain = false;
@@ -145,19 +137,19 @@ public:
145
137
 
146
138
  checkpointData = {
147
139
  {
148
- { 11111, uint256S("0x0000000069e244f73d78e8fd29ba2fd2ed618bd6fa2ee92559f542fdb26e7c1d")},
149
- { 33333, uint256S("0x000000002dd5588a74784eaa7ab0507a18ad16a236e7b1ce69f00d7ddfb5d0a6")},
150
- { 74000, uint256S("0x0000000000573993a3c9e41ce34471c079dcf5f52a0e824a81e7f953b8661a20")},
151
- {105000, uint256S("0x00000000000291ce28027faea320c8d2b054b2e0fe44a773f3eefb151d6bdc97")},
152
- {134444, uint256S("0x00000000000005b12ffd4cd315cd34ffd4a594f430ac814c91184a0d42d2b0fe")},
153
- {168000, uint256S("0x000000000000099e61ea72015e79632f216fe6cb33d7899acb35b75c8303b763")},
154
- {193000, uint256S("0x000000000000059f452a5f7340de6682a977387c17010ff6e6c3bd83ca8b1317")},
155
- {210000, uint256S("0x000000000000048b95347e83192f69cf0366076336c639f9b7228e9ba171342e")},
156
- {216116, uint256S("0x00000000000001b4f4b433e81ee46494af945cf96014816a4e2370f11b23df4e")},
157
- {225430, uint256S("0x00000000000001c108384350f74090433e7fcf79a606b8e797f065b130575932")},
158
- {250000, uint256S("0x000000000000003887df1f29024b06fc2200b55f8af8f35453d7be294df2d214")},
159
- {279000, uint256S("0x0000000000000001ae8c72a0b0c301f67e3afca10e819efa9041e458e9bd7e40")},
160
- {295000, uint256S("0x00000000000000004d9b4ef50f0f9d686fd69db2e03af35a100370c64632a983")},
140
+ { 0, uint256S("0x0000000032fe677166d54963b62a4677d8957e87c508eaa4fd7eb1c880cd27e3")},
141
+ { 19080, uint256S("0x000000000000bca54d9ac17881f94193fd6a270c1bb21c3bf0b37f588a40dbd7")},
142
+ { 30583, uint256S("0xd39d1481a7eecba48932ea5913be58ad3894c7ee6d5a8ba8abeb772c66a6696e")},
143
+ { 99999, uint256S("0x27fd5e1de16a4270eb8c68dee2754a64da6312c7c3a0e99a7e6776246be1ee3f")},
144
+ {219999, uint256S("0xab0dad4b10d2370f009ed6df6effca1ba42f01d5070d6b30afeedf6463fbe7a2")},
145
+ {336000, uint256S("0x4d261cef6e61a5ed8325e560f1d6e36f4698853a4c7134677f47a1d1d842bdf6")},
146
+ {371850, uint256S("0x6b18adcb0a6e080dae85b74eee2b83fabb157bbea64fab0ed2192b2f6d5b89f3")},
147
+ {407813, uint256S("0x00000000000000012730b0f48bed8afbeb08164c9d63597afb082e82ea05cec9")},
148
+ {443561, uint256S("0xf81cea8e4e40b2cfcc13a8bd82436399c35a55df951b95e7128601c1838029ed")},
149
+ {455470, uint256S("0xd1472c26229f90b8589d331aa47ba9023cb953b92dce342c753e7a6b3431bf1e")},
150
+ {479189, uint256S("0xc9c065028b20a23fbb9627bbca5946c7497f11e1f72433d4d215c79047cf06f2")},
151
+ {504051, uint256S("0xff65454ebdf1d89174bec10a3c016db92f7b1d9a4759603472842f254be8d7b3")},
152
+ {589659, uint256S("0x967c14abf21214639aeff0a270c4543cd3b80fe53178384ac5aa3c277662f1d0")},
161
153
  }
162
154
  };
163
155
 
@@ -166,10 +158,12 @@ public:
166
158
  };
167
159
 
168
160
  chainTxData = ChainTxData{
169
- // Data from RPC: getchaintxstats 4096 000000000000000000052d314a259755ca65944e68df6b12a067ea8f1f5a7091
170
- /* nTime */ 1645542140,
171
- /* nTxCount */ 712531200,
172
- /* dTxRate */ 2.891036496010309,
161
+ // Data as of block 967c14abf21214639aeff0a270c4543cd3b80fe53178384ac5aa3c277662f1d0 (height 589659).
162
+ 1635782211, // * UNIX timestamp of last known number of transactions
163
+ 1992832, // * total number of transactions between genesis and that timestamp
164
+ // (the tx=... number in the ChainStateFlushed debug.log lines)
165
+ 0.006862798 // * estimated number of transactions per second after that timestamp
166
+ // 1992832/(1635782211-1345400356) = 0.006862798
173
167
  };
174
168
  }
175
169
  };
@@ -183,57 +177,51 @@ public:
183
177
  strNetworkID = CBaseChainParams::TESTNET;
184
178
  consensus.signet_blocks = false;
185
179
  consensus.signet_challenge.clear();
186
- consensus.nSubsidyHalvingInterval = 210000;
187
- consensus.BIP16Exception = uint256S("0x00000000dd30457c001f4095d208cc1296b0eed002427aa599874af7a432b105");
188
- consensus.BIP34Height = 21111;
189
- consensus.BIP34Hash = uint256S("0x0000000023b3a96d3484e5abb3755c413e7d41500f8e2a5c3f0dd01299cd8ef8");
190
- consensus.BIP65Height = 581885; // 00000000007f6655f22f98e72ed80d8b06dc761d5da09df0fa1dc4be4f861eb6
191
- consensus.BIP66Height = 330776; // 000000002104c8c45e99a8853285a3b592602a3ccde2b832481da85e9e4ba182
192
- consensus.CSVHeight = 770112; // 00000000025e930139bac5c6c31a403776da130831ab85be56578f3fa75369bb
193
- consensus.SegwitHeight = 834624; // 00000000002b980fcd729daaa248fd9316a5200e9b367f4ff2c42453e84201ca
194
- consensus.MinBIP9WarningHeight = 836640; // segwit activation height + miner confirmation window
195
- consensus.powLimit = uint256S("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
196
- consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
197
- consensus.nPowTargetSpacing = 10 * 60;
180
+ //consensus.BIP16Height = 0;
181
+ consensus.BIP34Height = 293368;
182
+ consensus.BIP34Hash = uint256S("00000002c0b976c7a5c9878f1cec63fb4d88d68d614aedeaf8158c42d904795e");
183
+ consensus.powLimit = uint256S("0000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~arith_uint256(0) >> 28;
184
+ consensus.bnInitialHashTarget = uint256S("00000007ffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~arith_uint256(0) >> 29;
185
+
186
+ consensus.nTargetTimespan = 7 * 24 * 60 * 60; // one week
187
+ consensus.nStakeTargetSpacing = 10 * 60; // 10-minute block spacing
188
+ consensus.nTargetSpacingWorkMax = 12 * consensus.nStakeTargetSpacing; // 2-hour
189
+ consensus.nPowTargetSpacing = consensus.nStakeTargetSpacing;
190
+ consensus.nStakeMinAge = 60 * 60 * 24; // test net min age is 1 day
191
+ consensus.nStakeMaxAge = 60 * 60 * 24 * 90;
192
+ consensus.nModifierInterval = 60 * 20; // Modifier interval: time to elapse before new modifier is computed
193
+ consensus.nCoinbaseMaturity = 60;
194
+
198
195
  consensus.fPowAllowMinDifficultyBlocks = true;
199
196
  consensus.fPowNoRetargeting = false;
200
197
  consensus.nRuleChangeActivationThreshold = 1512; // 75% for testchains
201
198
  consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
202
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
203
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
204
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
205
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
206
199
 
207
- // Deployment of Taproot (BIPs 340-342)
208
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
209
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = 1619222400; // April 24th, 2021
210
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = 1628640000; // August 11th, 2021
211
- consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
200
+ consensus.SegwitHeight = 394215;
212
201
 
213
- consensus.nMinimumChainWork = uint256S("0x00000000000000000000000000000000000000000000064728c7be6fe4b2f961");
214
- consensus.defaultAssumeValid = uint256S("0x00000000000163cfb1f97c4e4098a3692c8053ad9cab5ad9c86b338b5c00b8b7"); // 2143398
202
+ consensus.nMinimumChainWork = uint256S("0x00");
203
+ consensus.defaultAssumeValid = uint256S("0x0000000002e9e7b00e1f6dc5123a04aad68dd0f0968d8c7aa45f6640795c37b1"); //1135275
215
204
 
216
- pchMessageStart[0] = 0x0b;
217
- pchMessageStart[1] = 0x11;
218
- pchMessageStart[2] = 0x09;
219
- pchMessageStart[3] = 0x07;
220
- nDefaultPort = 18333;
205
+ pchMessageStart[0] = 0xcb;
206
+ pchMessageStart[1] = 0xf2;
207
+ pchMessageStart[2] = 0xc0;
208
+ pchMessageStart[3] = 0xef;
209
+ nDefaultPort = 9903;
221
210
  nPruneAfterHeight = 1000;
222
- m_assumed_blockchain_size = 40;
223
- m_assumed_chain_state_size = 2;
211
+ m_assumed_blockchain_size = 2;
224
212
 
225
- genesis = CreateGenesisBlock(1296688602, 414098458, 0x1d00ffff, 1, 50 * COIN);
213
+ genesis = CreateGenesisBlock(1345083810, 1345090000, 122894938, 0x1d0fffff, 1, 0);
226
214
  consensus.hashGenesisBlock = genesis.GetHash();
227
- assert(consensus.hashGenesisBlock == uint256S("0x000000000933ea01ad0ee984209779baaec3ced90fa3f408719526f8d77f4943"));
228
- assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
215
+ assert(consensus.hashGenesisBlock == uint256S("0x00000001f757bb737f6596503e17cd17b0658ce630cc727c0cca81aec47c9f06"));
216
+ assert(genesis.hashMerkleRoot == uint256S("0x3c2d8f85fab4d17aac558cc648a1a58acff0de6deb890c29985690052c5993c2"));
229
217
 
230
218
  vFixedSeeds.clear();
231
219
  vSeeds.clear();
232
220
  // nodes with support for servicebits filtering should be at the top
233
- vSeeds.emplace_back("testnet-seed.bitcoin.jonasschnelli.ch.");
234
- vSeeds.emplace_back("seed.tbtc.petertodd.org.");
235
- vSeeds.emplace_back("seed.testnet.bitcoin.sprovoost.nl.");
236
- vSeeds.emplace_back("testnet-seed.bluematt.me."); // Just a static list of stable node(s), only supports x9
221
+ vSeeds.emplace_back("tseed.peercoin.net");
222
+ vSeeds.emplace_back("tseed2.peercoin.net");
223
+ vSeeds.emplace_back("tseed.peercoin-library.org");
224
+ vSeeds.emplace_back("testseed.ppcoin.info");
237
225
 
238
226
  base58Prefixes[PUBKEY_ADDRESS] = std::vector<unsigned char>(1,111);
239
227
  base58Prefixes[SCRIPT_ADDRESS] = std::vector<unsigned char>(1,196);
@@ -241,10 +229,12 @@ public:
241
229
  base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
242
230
  base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
243
231
 
244
- bech32_hrp = "tb";
232
+ // human readable prefix to bench32 address
233
+ bech32_hrp = "tpc";
245
234
 
246
235
  vFixedSeeds = std::vector<uint8_t>(std::begin(chainparams_seed_test), std::end(chainparams_seed_test));
247
236
 
237
+ fMiningRequiresPeers = true;
248
238
  fDefaultConsistencyChecks = false;
249
239
  fRequireStandard = false;
250
240
  m_is_test_chain = true;
@@ -252,7 +242,18 @@ public:
252
242
 
253
243
  checkpointData = {
254
244
  {
255
- {546, uint256S("000000002a936ca763904c3c35fce2f3556c559c0214345d31b1bcebf76acb70")},
245
+ { 0, uint256S("0x00000001f757bb737f6596503e17cd17b0658ce630cc727c0cca81aec47c9f06")},
246
+ { 19080, uint256S("0xb054d63d41852d71b611eaa8eca37d9fddca69b5013cf0966d453402ec8005ce")},
247
+ { 30583, uint256S("0x5179c0c496b5d25ab81ffe14273ea6928c6ff81c0a0d6a83b5d7d41d64886300")},
248
+ { 99999, uint256S("0xa7b03b14b8673683d972ab81775f3e85fea4fe689874b5956183466535dc651c")},
249
+ {219999, uint256S("0x0691bb86c92762c5c4c5a3723585ebeb7ec59310bbb0bdb6666551ab24ad919e")},
250
+ {336000, uint256S("0xf07adf61615c529f7c282b858d13d3e037b197324cb12e0669c461947494c4e3")},
251
+ {372751, uint256S("0x000000000000148db599b217c117b5104f5043c55f6ca2a8a065d9fab9f9bba1")},
252
+ {382019, uint256S("0x3ab75769d7957d9bf0857b5019d0a0e41044fa9ecf30b2f9c32aa457b0864ce5")},
253
+ {408500, uint256S("0x1636ac08b073d26b28fa40243d58dd5deb215752efe094c92c61998e4e9baf3f")},
254
+ {412691, uint256S("0x0e20318be88f07f521453435b37cfc516c3de07264a78ed7170985a1126126ab")},
255
+ {441299, uint256S("0x4091d0836a37c50ceee876000ac0cb251fd10031dab901d2c0677cd86283096e")},
256
+ {442735, uint256S("0x1b83b33894d51be0b8b323bfab093f638915236e0e40ba3b52bb33fdbc4053cd")},
256
257
  }
257
258
  };
258
259
 
@@ -261,10 +262,14 @@ public:
261
262
  };
262
263
 
263
264
  chainTxData = ChainTxData{
264
- // Data from RPC: getchaintxstats 4096 00000000d18cfe81cbeea665076807789bd8f831d557632e635bc6e3c003069e
265
- /* nTime */ 1645635119,
266
- /* nTxCount */ 62226341,
267
- /* dTxRate */ 0.07717997442177152,
265
+ // Data as of block 0x1b83b33894d51be0b8b323bfab093f638915236e0e40ba3b52bb33fdbc4053cd (height 442735)
266
+ 1632053274, // * UNIX timestamp of last known number of transactions
267
+ 863997, // * total number of transactions between genesis and that timestamp
268
+
269
+ // (the tx=... number in the SetBestChain debug.log lines)
270
+ 0.003020718 // * estimated number of transactions per second after that timestamp
271
+ // 863997/(1632053274-1346029522) = 0.003020718
272
+
268
273
  };
269
274
  }
270
275
  };
@@ -289,7 +294,6 @@ public:
289
294
  consensus.nMinimumChainWork = uint256S("0x000000000000000000000000000000000000000000000000000000de26b0e471");
290
295
  consensus.defaultAssumeValid = uint256S("0x00000112852484b5fe3451572368f93cfd2723279af3464e478aee35115256ef"); // 78788
291
296
  m_assumed_blockchain_size = 1;
292
- m_assumed_chain_state_size = 0;
293
297
  chainTxData = ChainTxData{
294
298
  // Data from RPC: getchaintxstats 4096 0000003d9144c56ac110ae04a0c271a0acce2f14f426b39fdf0d938c96d2eb09
295
299
  /* nTime */ 1645631279,
@@ -306,7 +310,6 @@ public:
306
310
  consensus.nMinimumChainWork = uint256{};
307
311
  consensus.defaultAssumeValid = uint256{};
308
312
  m_assumed_blockchain_size = 0;
309
- m_assumed_chain_state_size = 0;
310
313
  chainTxData = ChainTxData{
311
314
  0,
312
315
  0,
@@ -322,15 +325,12 @@ public:
322
325
  strNetworkID = CBaseChainParams::SIGNET;
323
326
  consensus.signet_blocks = true;
324
327
  consensus.signet_challenge.assign(bin.begin(), bin.end());
325
- consensus.nSubsidyHalvingInterval = 210000;
326
328
  consensus.BIP16Exception = uint256{};
327
329
  consensus.BIP34Height = 1;
328
330
  consensus.BIP34Hash = uint256{};
329
- consensus.BIP65Height = 1;
330
- consensus.BIP66Height = 1;
331
331
  consensus.CSVHeight = 1;
332
332
  consensus.SegwitHeight = 1;
333
- consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
333
+ // consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
334
334
  consensus.nPowTargetSpacing = 10 * 60;
335
335
  consensus.fPowAllowMinDifficultyBlocks = false;
336
336
  consensus.fPowNoRetargeting = false;
@@ -338,6 +338,7 @@ public:
338
338
  consensus.nMinerConfirmationWindow = 2016; // nPowTargetTimespan / nPowTargetSpacing
339
339
  consensus.MinBIP9WarningHeight = 0;
340
340
  consensus.powLimit = uint256S("00000377ae000000000000000000000000000000000000000000000000000000");
341
+ /*
341
342
  consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
342
343
  consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = Consensus::BIP9Deployment::NEVER_ACTIVE;
343
344
  consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
@@ -348,7 +349,7 @@ public:
348
349
  consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
349
350
  consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
350
351
  consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
351
-
352
+ */
352
353
  // message start is defined as the first 4 bytes of the sha256d of the block script
353
354
  CHashWriter h(SER_DISK, 0);
354
355
  h << consensus.signet_challenge;
@@ -358,10 +359,10 @@ public:
358
359
  nDefaultPort = 38333;
359
360
  nPruneAfterHeight = 1000;
360
361
 
361
- genesis = CreateGenesisBlock(1598918400, 52613770, 0x1e0377ae, 1, 50 * COIN);
362
+ genesis = CreateGenesisBlock(1345083810, 1345090000, 122894938, 0x1d0fffff, 1, 0);
362
363
  consensus.hashGenesisBlock = genesis.GetHash();
363
- assert(consensus.hashGenesisBlock == uint256S("0x00000008819873e925422c1ff0f99f7cc9bbb232af63a077a480a3633bee1ef6"));
364
- assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
364
+ assert(consensus.hashGenesisBlock == uint256S("0x00000001f757bb737f6596503e17cd17b0658ce630cc727c0cca81aec47c9f06"));
365
+ assert(genesis.hashMerkleRoot == uint256S("0x3c2d8f85fab4d17aac558cc648a1a58acff0de6deb890c29985690052c5993c2"));
365
366
 
366
367
  vFixedSeeds.clear();
367
368
 
@@ -384,70 +385,67 @@ public:
384
385
  * Regression test: intended for private networks only. Has minimal difficulty to ensure that
385
386
  * blocks can be found instantly.
386
387
  */
388
+
387
389
  class CRegTestParams : public CChainParams {
388
390
  public:
389
391
  explicit CRegTestParams(const ArgsManager& args) {
390
392
  strNetworkID = CBaseChainParams::REGTEST;
391
393
  consensus.signet_blocks = false;
392
394
  consensus.signet_challenge.clear();
393
- consensus.nSubsidyHalvingInterval = 150;
394
395
  consensus.BIP16Exception = uint256();
395
396
  consensus.BIP34Height = 1; // Always active unless overridden
396
397
  consensus.BIP34Hash = uint256();
397
- consensus.BIP65Height = 1; // Always active unless overridden
398
- consensus.BIP66Height = 1; // Always active unless overridden
399
- consensus.CSVHeight = 1; // Always active unless overridden
400
- consensus.SegwitHeight = 0; // Always active unless overridden
401
- consensus.MinBIP9WarningHeight = 0;
402
- consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff");
403
- consensus.nPowTargetTimespan = 14 * 24 * 60 * 60; // two weeks
404
- consensus.nPowTargetSpacing = 10 * 60;
398
+ consensus.powLimit = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~arith_uint256(0) >> 28;
399
+ consensus.bnInitialHashTarget = uint256S("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"); // ~arith_uint256(0) >> 29;
400
+
401
+ consensus.nTargetTimespan = 7 * 24 * 60 * 60; // two weeks
402
+ consensus.nStakeTargetSpacing = 10 * 60; // 10-minute block spacing
403
+ consensus.nTargetSpacingWorkMax = 12 * consensus.nStakeTargetSpacing; // 2-hour
404
+ consensus.nPowTargetSpacing = consensus.nStakeTargetSpacing;
405
+
406
+ consensus.nStakeMinAge = 60 * 60 * 24; // test net min age is 1 day
407
+ consensus.nStakeMaxAge = 60 * 60 * 24 * 90;
408
+ consensus.nModifierInterval = 60 * 20; // Modifier interval: time to elapse before new modifier is computed
409
+ consensus.nCoinbaseMaturity = 60;
410
+
405
411
  consensus.fPowAllowMinDifficultyBlocks = true;
406
412
  consensus.fPowNoRetargeting = true;
407
413
  consensus.nRuleChangeActivationThreshold = 108; // 75% for testchains
408
414
  consensus.nMinerConfirmationWindow = 144; // Faster than normal for regtest (144 instead of 2016)
409
-
410
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].bit = 28;
411
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nStartTime = 0;
412
- consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
415
+ /*
413
416
  consensus.vDeployments[Consensus::DEPLOYMENT_TESTDUMMY].min_activation_height = 0; // No activation delay
414
417
 
415
418
  consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].bit = 2;
416
419
  consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nStartTime = Consensus::BIP9Deployment::ALWAYS_ACTIVE;
417
420
  consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].nTimeout = Consensus::BIP9Deployment::NO_TIMEOUT;
418
421
  consensus.vDeployments[Consensus::DEPLOYMENT_TAPROOT].min_activation_height = 0; // No activation delay
419
-
422
+ */
420
423
  consensus.nMinimumChainWork = uint256{};
421
424
  consensus.defaultAssumeValid = uint256{};
422
425
 
423
- pchMessageStart[0] = 0xfa;
424
- pchMessageStart[1] = 0xbf;
425
- pchMessageStart[2] = 0xb5;
426
- pchMessageStart[3] = 0xda;
427
- nDefaultPort = 18444;
428
- nPruneAfterHeight = args.GetBoolArg("-fastprune", false) ? 100 : 1000;
426
+ pchMessageStart[0] = 0xcb;
427
+ pchMessageStart[1] = 0xf2;
428
+ pchMessageStart[2] = 0xc0;
429
+ pchMessageStart[3] = 0xef;
430
+ nDefaultPort = 9903;
431
+ nPruneAfterHeight = 1000;
429
432
  m_assumed_blockchain_size = 0;
430
- m_assumed_chain_state_size = 0;
431
433
 
432
- UpdateActivationParametersFromArgs(args);
434
+ genesis = CreateGenesisBlock(1345083810, 1345090000, 122894938, 0x1d0fffff, 1, 0);
433
435
 
434
- genesis = CreateGenesisBlock(1296688602, 2, 0x207fffff, 1, 50 * COIN);
435
436
  consensus.hashGenesisBlock = genesis.GetHash();
436
- assert(consensus.hashGenesisBlock == uint256S("0x0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206"));
437
- assert(genesis.hashMerkleRoot == uint256S("0x4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b"));
437
+ assert(consensus.hashGenesisBlock == uint256S("0x00000001f757bb737f6596503e17cd17b0658ce630cc727c0cca81aec47c9f06"));
438
+ assert(genesis.hashMerkleRoot == uint256S("0x3c2d8f85fab4d17aac558cc648a1a58acff0de6deb890c29985690052c5993c2"));
438
439
 
439
440
  vFixedSeeds.clear(); //!< Regtest mode doesn't have any fixed seeds.
440
441
  vSeeds.clear();
441
442
  vSeeds.emplace_back("dummySeed.invalid.");
442
443
 
443
- fDefaultConsistencyChecks = true;
444
- fRequireStandard = true;
445
444
  m_is_test_chain = true;
446
445
  m_is_mockable_chain = true;
447
-
448
446
  checkpointData = {
449
447
  {
450
- {0, uint256S("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206")},
448
+ {0, uint256S("0x00000001f757bb737f6596503e17cd17b0658ce630cc727c0cca81aec47c9f06")},
451
449
  }
452
450
  };
453
451
 
@@ -474,17 +472,11 @@ public:
474
472
  base58Prefixes[EXT_PUBLIC_KEY] = {0x04, 0x35, 0x87, 0xCF};
475
473
  base58Prefixes[EXT_SECRET_KEY] = {0x04, 0x35, 0x83, 0x94};
476
474
 
477
- bech32_hrp = "bcrt";
478
- }
479
-
480
- /**
481
- * Allows modifying the Version Bits regtest parameters.
482
- */
483
- void UpdateVersionBitsParameters(Consensus::DeploymentPos d, int64_t nStartTime, int64_t nTimeout, int min_activation_height)
484
- {
485
- consensus.vDeployments[d].nStartTime = nStartTime;
486
- consensus.vDeployments[d].nTimeout = nTimeout;
487
- consensus.vDeployments[d].min_activation_height = min_activation_height;
475
+ bech32_hrp = "pcrt";
476
+ fMiningRequiresPeers = false;
477
+ fDefaultConsistencyChecks = true;
478
+ fRequireStandard = false;
479
+ //fMineBlocksOnDemand = true;
488
480
  }
489
481
  void UpdateActivationParametersFromArgs(const ArgsManager& args);
490
482
  };
@@ -507,9 +499,9 @@ static void MaybeUpdateHeights(const ArgsManager& args, Consensus::Params& conse
507
499
  } else if (name == "bip34") {
508
500
  consensus.BIP34Height = int{height};
509
501
  } else if (name == "dersig") {
510
- consensus.BIP66Height = int{height};
502
+ //consensus.BIP66Height = int{height};
511
503
  } else if (name == "cltv") {
512
- consensus.BIP65Height = int{height};
504
+ //consensus.BIP65Height = int{height};
513
505
  } else if (name == "csv") {
514
506
  consensus.CSVHeight = int{height};
515
507
  } else {
@@ -521,40 +513,7 @@ static void MaybeUpdateHeights(const ArgsManager& args, Consensus::Params& conse
521
513
  void CRegTestParams::UpdateActivationParametersFromArgs(const ArgsManager& args)
522
514
  {
523
515
  MaybeUpdateHeights(args, consensus);
524
-
525
- if (!args.IsArgSet("-vbparams")) return;
526
-
527
- for (const std::string& strDeployment : args.GetArgs("-vbparams")) {
528
- std::vector<std::string> vDeploymentParams;
529
- boost::split(vDeploymentParams, strDeployment, boost::is_any_of(":"));
530
- if (vDeploymentParams.size() < 3 || 4 < vDeploymentParams.size()) {
531
- throw std::runtime_error("Version bits parameters malformed, expecting deployment:start:end[:min_activation_height]");
532
- }
533
- int64_t nStartTime, nTimeout;
534
- int min_activation_height = 0;
535
- if (!ParseInt64(vDeploymentParams[1], &nStartTime)) {
536
- throw std::runtime_error(strprintf("Invalid nStartTime (%s)", vDeploymentParams[1]));
537
- }
538
- if (!ParseInt64(vDeploymentParams[2], &nTimeout)) {
539
- throw std::runtime_error(strprintf("Invalid nTimeout (%s)", vDeploymentParams[2]));
540
- }
541
- if (vDeploymentParams.size() >= 4 && !ParseInt32(vDeploymentParams[3], &min_activation_height)) {
542
- throw std::runtime_error(strprintf("Invalid min_activation_height (%s)", vDeploymentParams[3]));
543
- }
544
- bool found = false;
545
- for (int j=0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) {
546
- if (vDeploymentParams[0] == VersionBitsDeploymentInfo[j].name) {
547
- UpdateVersionBitsParameters(Consensus::DeploymentPos(j), nStartTime, nTimeout, min_activation_height);
548
- found = true;
549
- LogPrintf("Setting version bits activation parameters for %s to start=%ld, timeout=%ld, min_activation_height=%d\n", vDeploymentParams[0], nStartTime, nTimeout, min_activation_height);
550
- break;
551
- }
552
- }
553
- if (!found) {
554
- throw std::runtime_error(strprintf("Invalid deployment (%s)", vDeploymentParams[0]));
555
- }
556
- }
557
- }
516
+ }
558
517
 
559
518
  static std::unique_ptr<const CChainParams> globalChainParams;
560
519
 
src/chainparams.h CHANGED
@@ -93,6 +93,8 @@ public:
93
93
  }
94
94
 
95
95
  const CBlock& GenesisBlock() const { return genesis; }
96
+ /** Make miner wait to have peers to avoid wasting work */
97
+ bool MiningRequiresPeers() const { return fMiningRequiresPeers; }
96
98
  /** Default value for -checkmempool and -checkblockindex argument */
97
99
  bool DefaultConsistencyChecks() const { return fDefaultConsistencyChecks; }
98
100
  /** Policy: Filter transactions that do not match well-defined patterns */
@@ -104,8 +106,6 @@ public:
104
106
  uint64_t PruneAfterHeight() const { return nPruneAfterHeight; }
105
107
  /** Minimum free space (in GB) needed for data directory */
106
108
  uint64_t AssumedBlockchainSize() const { return m_assumed_blockchain_size; }
107
- /** Minimum free space (in GB) needed for data directory when pruned; Does not include prune target*/
108
- uint64_t AssumedChainStateSize() const { return m_assumed_chain_state_size; }
109
109
  /** Whether it is possible to mine blocks on demand (no retargeting) */
110
110
  bool MineBlocksOnDemand() const { return consensus.fPowNoRetargeting; }
111
111
  /** Return the network string */
@@ -130,13 +130,13 @@ protected:
130
130
  uint16_t nDefaultPort;
131
131
  uint64_t nPruneAfterHeight;
132
132
  uint64_t m_assumed_blockchain_size;
133
- uint64_t m_assumed_chain_state_size;
134
133
  std::vector<std::string> vSeeds;
135
134
  std::vector<unsigned char> base58Prefixes[MAX_BASE58_TYPES];
136
135
  std::string bech32_hrp;
137
136
  std::string strNetworkID;
138
137
  CBlock genesis;
139
138
  std::vector<uint8_t> vFixedSeeds;
139
+ bool fMiningRequiresPeers;
140
140
  bool fDefaultConsistencyChecks;
141
141
  bool fRequireStandard;
142
142
  bool m_is_test_chain;
src/chainparamsbase.cpp CHANGED
@@ -43,13 +43,13 @@ const CBaseChainParams& BaseParams()
43
43
  std::unique_ptr<CBaseChainParams> CreateBaseChainParams(const std::string& chain)
44
44
  {
45
45
  if (chain == CBaseChainParams::MAIN) {
46
- return std::make_unique<CBaseChainParams>("", 8332, 8334);
46
+ return std::make_unique<CBaseChainParams>("", 9902, 9903);
47
47
  } else if (chain == CBaseChainParams::TESTNET) {
48
- return std::make_unique<CBaseChainParams>("testnet3", 18332, 18334);
48
+ return std::make_unique<CBaseChainParams>("testnet3", 9904, 9905);
49
49
  } else if (chain == CBaseChainParams::SIGNET) {
50
50
  return std::make_unique<CBaseChainParams>("signet", 38332, 38334);
51
51
  } else if (chain == CBaseChainParams::REGTEST) {
52
- return std::make_unique<CBaseChainParams>("regtest", 18443, 18445);
52
+ return std::make_unique<CBaseChainParams>("regtest", 18443, 18444);
53
53
  }
54
54
  throw std::runtime_error(strprintf("%s: Unknown chain %s.", __func__, chain));
55
55
  }
src/clientversion.cpp CHANGED
@@ -18,6 +18,7 @@
18
18
  */
19
19
  const std::string CLIENT_NAME("Satoshi");
20
20
 
21
+ #define CLIENT_VERSION_SUFFIX " Coccinellidae"
21
22
 
22
23
  #ifdef HAVE_BUILD_INFO
23
24
  #include <obj/build.h>
@@ -34,7 +35,8 @@ const std::string CLIENT_NAME("Satoshi");
34
35
  #define BUILD_DESC BUILD_GIT_TAG
35
36
  #define BUILD_SUFFIX ""
36
37
  #else
37
- #define BUILD_DESC "v" PACKAGE_VERSION
38
+ #define BUILD_DESC "v" STRINGIZE(PEERCOIN_VERSION_MAJOR) "." STRINGIZE(PEERCOIN_VERSION_MINOR) \
39
+ "." STRINGIZE(PEERCOIN_VERSION_REVISION) "." STRINGIZE(PEERCOIN_VERSION_BUILD)
38
40
  #if CLIENT_VERSION_IS_RELEASE
39
41
  #define BUILD_SUFFIX ""
40
42
  #elif defined(BUILD_GIT_COMMIT)
@@ -53,7 +55,7 @@ static std::string FormatVersion(int nVersion)
53
55
 
54
56
  std::string FormatFullVersion()
55
57
  {
56
- static const std::string CLIENT_BUILD(BUILD_DESC BUILD_SUFFIX);
58
+ static const std::string CLIENT_BUILD(BUILD_DESC CLIENT_VERSION_SUFFIX);
57
59
  return CLIENT_BUILD;
58
60
  }
59
61
 
@@ -74,6 +76,8 @@ std::string FormatSubVersion(const std::string& name, int nClientVersion, const
74
76
  ss << ")";
75
77
  }
76
78
  ss << "/";
79
+ ss << "Peercoin:" << FormatVersion(PEERCOIN_VERSION);
80
+ ss << "(" << FormatFullVersion() << ")/";
77
81
  return ss.str();
78
82
  }
79
83
 
@@ -91,7 +95,7 @@ std::string CopyrightHolders(const std::string& strPrefix)
91
95
 
92
96
  std::string LicenseInfo()
93
97
  {
94
- const std::string URL_SOURCE_CODE = "<https://github.com/bitcoin/bitcoin>";
98
+ const std::string URL_SOURCE_CODE = "<https://github.com/peercoin/peercoin>";
95
99
 
96
100
  return CopyrightHolders(strprintf(_("Copyright (C) %i-%i").translated, 2009, COPYRIGHT_YEAR) + " ") + "\n" +
97
101
  "\n" +
src/clientversion.h CHANGED
@@ -12,7 +12,7 @@
12
12
  #endif //HAVE_CONFIG_H
13
13
 
14
14
  // Check that required client information is defined
15
- #if !defined(CLIENT_VERSION_MAJOR) || !defined(CLIENT_VERSION_MINOR) || !defined(CLIENT_VERSION_BUILD) || !defined(CLIENT_VERSION_IS_RELEASE) || !defined(COPYRIGHT_YEAR)
15
+ #if !defined(PEERCOIN_VERSION_MAJOR) || !defined(PEERCOIN_VERSION_MINOR) || !defined(PEERCOIN_VERSION_REVISION) || !defined(PEERCOIN_VERSION_BUILD)
16
16
  #error Client version information missing: version is not defined by bitcoin-config.h or in any other way
17
17
  #endif
18
18
 
@@ -35,6 +35,13 @@ static const int CLIENT_VERSION =
35
35
  + 100 * CLIENT_VERSION_MINOR
36
36
  + 1 * CLIENT_VERSION_BUILD;
37
37
 
38
+ // note: peercoin version is used for display purpose AND to accept alerts
39
+ static const int PEERCOIN_VERSION =
40
+ 1000000 * PEERCOIN_VERSION_MAJOR
41
+ + 10000 * PEERCOIN_VERSION_MINOR
42
+ + 100 * PEERCOIN_VERSION_REVISION
43
+ + 1 * PEERCOIN_VERSION_BUILD;
44
+
38
45
  extern const std::string CLIENT_NAME;
39
46
 
40
47
 
src/coins.cpp CHANGED
@@ -64,9 +64,10 @@ bool CCoinsViewCache::GetCoin(const COutPoint &outpoint, Coin &coin) const {
64
64
  return false;
65
65
  }
66
66
 
67
- void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possible_overwrite) {
67
+ void CCoinsViewCache::AddCoin(const COutPoint &outpoint, Coin&& coin, bool possible_overwrite, bool skipZeroValue) {
68
68
  assert(!coin.IsSpent());
69
69
  if (coin.out.scriptPubKey.IsUnspendable()) return;
70
+ if (coin.out.nValue == 0 && skipZeroValue) return;
70
71
  CCoinsMap::iterator it;
71
72
  bool inserted;
72
73
  std::tie(it, inserted) = cacheCoins.emplace(std::piecewise_construct, std::forward_as_tuple(outpoint), std::tuple<>());
@@ -112,14 +113,14 @@ void CCoinsViewCache::EmplaceCoinInternalDANGER(COutPoint&& outpoint, Coin&& coi
112
113
  std::forward_as_tuple(std::move(coin), CCoinsCacheEntry::DIRTY));
113
114
  }
114
115
 
115
- void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight, bool check_for_overwrite) {
116
+ void AddCoins(CCoinsViewCache& cache, const CTransaction &tx, int nHeight, bool check_for_overwrite, bool skipZeroValue) {
116
117
  bool fCoinbase = tx.IsCoinBase();
117
118
  const uint256& txid = tx.GetHash();
118
119
  for (size_t i = 0; i < tx.vout.size(); ++i) {
119
120
  bool overwrite = check_for_overwrite ? cache.HaveCoin(COutPoint(txid, i)) : fCoinbase;
120
121
  // Coinbase transactions can always be overwritten, in order to correctly
121
122
  // deal with the pre-BIP30 occurrences of duplicate coinbase transactions.
122
- cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, fCoinbase), overwrite);
123
+ cache.AddCoin(COutPoint(txid, i), Coin(tx.vout[i], nHeight, fCoinbase, tx.IsCoinStake(), tx.nTime), overwrite, skipZeroValue);
123
124
  }
124
125
  }
125
126
 
src/coins.h CHANGED
@@ -39,29 +39,48 @@ public:
39
39
  //! at which height this containing transaction was included in the active block chain
40
40
  uint32_t nHeight : 31;
41
41
 
42
+ // peercoin: whether transaction is a coinstake
43
+ bool fCoinStake;
44
+
45
+ // peercoin: transaction timestamp
46
+ unsigned int nTime;
47
+
42
48
  //! construct a Coin from a CTxOut and height/coinbase information.
43
- Coin(CTxOut&& outIn, int nHeightIn, bool fCoinBaseIn) : out(std::move(outIn)), fCoinBase(fCoinBaseIn), nHeight(nHeightIn) {}
44
- Coin(const CTxOut& outIn, int nHeightIn, bool fCoinBaseIn) : out(outIn), fCoinBase(fCoinBaseIn),nHeight(nHeightIn) {}
49
+ Coin(CTxOut&& outIn, int nHeightIn, bool fCoinBaseIn, bool fCoinStakeIn, int nTimeIn) :
50
+ out(std::move(outIn)), fCoinBase(fCoinBaseIn), nHeight(nHeightIn), fCoinStake(fCoinStakeIn), nTime(nTimeIn) {}
51
+ Coin(const CTxOut& outIn, int nHeightIn, bool fCoinBaseIn, bool fCoinStakeIn, int nTimeIn) :
52
+ out(outIn), fCoinBase(fCoinBaseIn), nHeight(nHeightIn), fCoinStake(fCoinStakeIn), nTime(nTimeIn) {}
45
53
 
46
54
  void Clear() {
47
55
  out.SetNull();
48
56
  fCoinBase = false;
49
57
  nHeight = 0;
58
+ fCoinStake = false;
59
+ nTime = 0;
50
60
  }
51
61
 
52
62
  //! empty constructor
53
- Coin() : fCoinBase(false), nHeight(0) { }
63
+ Coin() : fCoinBase(false), nHeight(0), fCoinStake(false), nTime(0) { }
54
64
 
55
65
  bool IsCoinBase() const {
56
66
  return fCoinBase;
57
67
  }
58
68
 
69
+ bool IsCoinStake() const { // peercoin: coinstake
70
+ return fCoinStake;
71
+ }
72
+
59
73
  template<typename Stream>
60
74
  void Serialize(Stream &s) const {
61
75
  assert(!IsSpent());
62
76
  uint32_t code = nHeight * uint32_t{2} + fCoinBase;
63
77
  ::Serialize(s, VARINT(code));
64
78
  ::Serialize(s, Using<TxOutCompression>(out));
79
+ // peercoin flags
80
+ unsigned int nFlag = fCoinStake? 1 : 0;
81
+ ::Serialize(s, VARINT(nFlag));
82
+ // peercoin transaction timestamp
83
+ ::Serialize(s, VARINT(nTime));
65
84
  }
66
85
 
67
86
  template<typename Stream>
@@ -71,6 +90,12 @@ public:
71
90
  nHeight = code >> 1;
72
91
  fCoinBase = code & 1;
73
92
  ::Unserialize(s, Using<TxOutCompression>(out));
93
+ // peercoin flags
94
+ unsigned int nFlag = 0;
95
+ ::Unserialize(s, VARINT(nFlag));
96
+ fCoinStake = nFlag & 1;
97
+ // peercoin transaction timestamp
98
+ ::Unserialize(s, VARINT(nTime));
74
99
  }
75
100
 
76
101
  /** Either this coin never existed (see e.g. coinEmpty in coins.cpp), or it
@@ -264,7 +289,7 @@ public:
264
289
  * Add a coin. Set possible_overwrite to true if an unspent version may
265
290
  * already exist in the cache.
266
291
  */
267
- void AddCoin(const COutPoint& outpoint, Coin&& coin, bool possible_overwrite);
292
+ void AddCoin(const COutPoint& outpoint, Coin&& coin, bool possible_overwrite, bool skipZeroValue = false);
268
293
 
269
294
  /**
270
295
  * Emplace a coin into cacheCoins without performing any checks, marking
@@ -325,7 +350,7 @@ private:
325
350
  //! an overwrite.
326
351
  // TODO: pass in a boolean to limit these possible overwrites to known
327
352
  // (pre-BIP34) cases.
328
- void AddCoins(CCoinsViewCache& cache, const CTransaction& tx, int nHeight, bool check = false);
353
+ void AddCoins(CCoinsViewCache& cache, const CTransaction& tx, int nHeight, bool check = false, bool skipZeroValue = false);
329
354
 
330
355
  //! Utility function to find any unspent output with a given txid.
331
356
  //! This function can be quite expensive because in the event of a transaction
src/consensus/amount.h CHANGED
@@ -7,12 +7,22 @@
7
7
  #define BITCOIN_CONSENSUS_AMOUNT_H
8
8
 
9
9
  #include <cstdint>
10
+ #include <string>
10
11
 
11
12
  /** Amount in satoshis (Can be negative) */
12
13
  typedef int64_t CAmount;
13
14
 
14
- /** The amount of satoshis in one BTC. */
15
- static constexpr CAmount COIN = 100000000;
15
+ static constexpr CAmount COIN = 1000000;
16
+ static constexpr CAmount CENT = 10000;
17
+
18
+ static const CAmount MIN_TX_FEE_PREV7 = CENT;
19
+ static const CAmount MIN_TX_FEE = CENT / 10;
20
+ static const CAmount PERKB_TX_FEE = CENT;
21
+ static const CAmount MIN_TXOUT_AMOUNT = CENT;
22
+ static const CAmount MAX_MINT_PROOF_OF_WORK = 9999 * COIN;
23
+ static const CAmount MAX_MINT_PROOF_OF_WORK_V10 = 50 * COIN;
24
+ static const std::string CURRENCY_UNIT = "PPC";
25
+ static const std::string CURRENCY_ATOM = "sat"; // One indivisible minimum value unit
16
26
 
17
27
  /** No amount larger than this (in satoshi) is valid.
18
28
  *
src/consensus/params.h CHANGED
@@ -33,52 +33,16 @@ enum DeploymentPos : uint16_t {
33
33
  };
34
34
  constexpr bool ValidDeployment(DeploymentPos dep) { return dep < MAX_VERSION_BITS_DEPLOYMENTS; }
35
35
 
36
- /**
37
- * Struct for each individual consensus rule change using BIP9.
38
- */
39
- struct BIP9Deployment {
40
- /** Bit position to select the particular bit in nVersion. */
41
- int bit;
42
- /** Start MedianTime for version bits miner confirmation. Can be a date in the past */
43
- int64_t nStartTime;
44
- /** Timeout/expiry MedianTime for the deployment attempt. */
45
- int64_t nTimeout;
46
- /** If lock in occurs, delay activation until at least this block
47
- * height. Note that activation will only occur on a retarget
48
- * boundary.
49
- */
50
- int min_activation_height{0};
51
-
52
- /** Constant for nTimeout very far in the future. */
53
- static constexpr int64_t NO_TIMEOUT = std::numeric_limits<int64_t>::max();
54
-
55
- /** Special value for nStartTime indicating that the deployment is always active.
56
- * This is useful for testing, as it means tests don't need to deal with the activation
57
- * process (which takes at least 3 BIP9 intervals). Only tests that specifically test the
58
- * behaviour during activation cannot use this. */
59
- static constexpr int64_t ALWAYS_ACTIVE = -1;
60
-
61
- /** Special value for nStartTime indicating that the deployment is never active.
62
- * This is useful for integrating the code changes for a new feature
63
- * prior to deploying it on some or all networks. */
64
- static constexpr int64_t NEVER_ACTIVE = -2;
65
- };
66
-
67
36
  /**
68
37
  * Parameters that influence chain consensus.
69
38
  */
70
39
  struct Params {
71
40
  uint256 hashGenesisBlock;
72
- int nSubsidyHalvingInterval;
73
41
  /* Block hash that is excepted from BIP16 enforcement */
74
42
  uint256 BIP16Exception;
75
43
  /** Block height and hash at which BIP34 becomes active */
76
44
  int BIP34Height;
77
45
  uint256 BIP34Hash;
78
- /** Block height at which BIP65 becomes active */
79
- int BIP65Height;
80
- /** Block height at which BIP66 becomes active */
81
- int BIP66Height;
82
46
  /** Block height at which CSV (BIP68, BIP112 and BIP113) becomes active */
83
47
  int CSVHeight;
84
48
  /** Block height at which Segwit (BIP141, BIP143 and BIP147) becomes active.
@@ -90,19 +54,16 @@ struct Params {
90
54
  int MinBIP9WarningHeight;
91
55
  /**
92
56
  * Minimum blocks including miner confirmation of the total of 2016 blocks in a retargeting period,
93
- * (nPowTargetTimespan / nPowTargetSpacing) which is also used for BIP9 deployments.
57
+ * (nPowTargetTimespan / nPowTargetSpacing)
94
58
  * Examples: 1916 for 95%, 1512 for testchains.
95
59
  */
96
60
  uint32_t nRuleChangeActivationThreshold;
97
61
  uint32_t nMinerConfirmationWindow;
98
- BIP9Deployment vDeployments[MAX_VERSION_BITS_DEPLOYMENTS];
99
62
  /** Proof of work parameters */
100
63
  uint256 powLimit;
101
64
  bool fPowAllowMinDifficultyBlocks;
102
65
  bool fPowNoRetargeting;
103
66
  int64_t nPowTargetSpacing;
104
- int64_t nPowTargetTimespan;
105
- int64_t DifficultyAdjustmentInterval() const { return nPowTargetTimespan / nPowTargetSpacing; }
106
67
  /** The best chain should have at least this much work */
107
68
  uint256 nMinimumChainWork;
108
69
  /** By default assume that the signatures in ancestors of this block are valid */
@@ -114,23 +75,15 @@ struct Params {
114
75
  */
115
76
  bool signet_blocks{false};
116
77
  std::vector<uint8_t> signet_challenge;
117
-
118
- int DeploymentHeight(BuriedDeployment dep) const
119
- {
120
- switch (dep) {
121
- case DEPLOYMENT_HEIGHTINCB:
122
- return BIP34Height;
123
- case DEPLOYMENT_CLTV:
124
- return BIP65Height;
125
- case DEPLOYMENT_DERSIG:
126
- return BIP66Height;
127
- case DEPLOYMENT_CSV:
128
- return CSVHeight;
129
- case DEPLOYMENT_SEGWIT:
130
- return SegwitHeight;
131
- } // no default case, so the compiler can warn about missing cases
132
- return std::numeric_limits<int>::max();
133
- }
78
+ /** peercoin stuff */
79
+ uint256 bnInitialHashTarget;
80
+ int64_t nStakeTargetSpacing;
81
+ int64_t nTargetSpacingWorkMax;
82
+ int64_t nTargetTimespan;
83
+ int64_t nStakeMinAge;
84
+ int64_t nStakeMaxAge;
85
+ int64_t nModifierInterval;
86
+ int nCoinbaseMaturity; // Coinbase transaction outputs can only be spent after this number of new blocks (network rule)
134
87
  };
135
88
 
136
89
  } // namespace Consensus
src/consensus/tx_check.cpp CHANGED
@@ -7,6 +7,12 @@
7
7
  #include <consensus/amount.h>
8
8
  #include <primitives/transaction.h>
9
9
  #include <consensus/validation.h>
10
+ #include <chainparams.h>
11
+
12
+ bool IsZeroAllowed(const unsigned int nTimeTx)
13
+ {
14
+ return (nTimeTx >= 1447700000 ); // very crude approximation to prevent linking with kernel.cpp
15
+ }
10
16
 
11
17
  bool CheckTransaction(const CTransaction& tx, TxValidationState& state)
12
18
  {
@@ -30,6 +36,10 @@ bool CheckTransaction(const CTransaction& tx, TxValidationState& state)
30
36
  nValueOut += txout.nValue;
31
37
  if (!MoneyRange(nValueOut))
32
38
  return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-txouttotal-toolarge");
39
+ // peercoin: enforce minimum output amount
40
+ if ((!txout.IsEmpty()) && txout.nValue < MIN_TXOUT_AMOUNT &&
41
+ (tx.nVersion < 3 && !(IsZeroAllowed(tx.nTime) && (txout.nValue == 0))))
42
+ return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-txoutvalue-belowminimum");
33
43
  }
34
44
 
35
45
  // Check for duplicate inputs (see CVE-2018-17144)
src/consensus/tx_verify.cpp CHANGED
@@ -11,6 +11,9 @@
11
11
  #include <consensus/validation.h>
12
12
  #include <primitives/transaction.h>
13
13
  #include <script/interpreter.h>
14
+ #include <kernel.h>
15
+ #include <validation.h> // GetCoinAge()
16
+
14
17
  #include <util/moneystr.h>
15
18
 
16
19
  bool IsFinalTx(const CTransaction &tx, int nBlockHeight, int64_t nBlockTime)
@@ -164,7 +167,7 @@ int64_t GetTransactionSigOpCost(const CTransaction& tx, const CCoinsViewCache& i
164
167
  return nSigOps;
165
168
  }
166
169
 
167
- bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee)
170
+ bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee, const Consensus::Params& params, unsigned int nTimeTx, uint64_t nMoneySupply)
168
171
  {
169
172
  // are the actual inputs available?
170
173
  if (!inputs.HaveInputs(tx)) {
@@ -179,11 +182,15 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state,
179
182
  assert(!coin.IsSpent());
180
183
 
181
184
  // If prev is coinbase, check that it's matured
182
- if (coin.IsCoinBase() && nSpendHeight - coin.nHeight < COINBASE_MATURITY) {
183
- return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "bad-txns-premature-spend-of-coinbase",
185
+ if ((coin.IsCoinBase() || coin.IsCoinStake()) && nSpendHeight - coin.nHeight < params.nCoinbaseMaturity) {
186
+ return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "bad-txns-premature-spend-of-coinbase/coinstake",
184
187
  strprintf("tried to spend coinbase at depth %d", nSpendHeight - coin.nHeight));
185
188
  }
186
189
 
190
+ // peercoin: check transaction timestamp
191
+ if (coin.nTime > nTimeTx)
192
+ return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-spent-too-early", strprintf("%s : transaction timestamp earlier than input transaction", __func__));
193
+
187
194
  // Check for negative or overflow input values
188
195
  nValueIn += coin.out.nValue;
189
196
  if (!MoneyRange(coin.out.nValue) || !MoneyRange(nValueIn)) {
@@ -191,18 +198,52 @@ bool Consensus::CheckTxInputs(const CTransaction& tx, TxValidationState& state,
191
198
  }
192
199
  }
193
200
 
194
- const CAmount value_out = tx.GetValueOut();
195
- if (nValueIn < value_out) {
196
- return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-in-belowout",
197
- strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
201
+ if (tx.IsCoinStake())
202
+ {
203
+ // peercoin: coin stake tx earns reward instead of paying fee
204
+ uint64_t nCoinAge;
205
+ if (!GetCoinAge(tx, inputs, nCoinAge, nTimeTx))
206
+ return state.Invalid(TxValidationResult::TX_CONSENSUS, "unable to get coin age for coinstake");
207
+ CAmount nStakeReward = tx.GetValueOut() - nValueIn;
208
+ CAmount nCoinstakeCost = (GetMinFee(tx, nTimeTx) < PERKB_TX_FEE) ? 0 : (GetMinFee(tx, nTimeTx) - PERKB_TX_FEE);
209
+ if (nMoneySupply && nStakeReward > GetProofOfStakeReward(nCoinAge, nTimeTx, nMoneySupply) - nCoinstakeCost)
210
+ return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-coinstake-too-large");
198
211
  }
199
-
200
- // Tally transaction fees
201
- const CAmount txfee_aux = nValueIn - value_out;
202
- if (!MoneyRange(txfee_aux)) {
203
- return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-fee-outofrange");
212
+ else
213
+ {
214
+ const CAmount value_out = tx.GetValueOut();
215
+ if (nValueIn < value_out) {
216
+ return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-in-belowout",
217
+ strprintf("value in (%s) < value out (%s)", FormatMoney(nValueIn), FormatMoney(value_out)));
218
+ }
219
+ // Tally transaction fees
220
+ const CAmount txfee_aux = nValueIn - value_out;
221
+ if (!MoneyRange(txfee_aux)) {
222
+ return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-fee-outofrange");
223
+ }
224
+ // peercoin: enforce transaction fees for every block
225
+ if (txfee_aux < GetMinFee(tx, nTimeTx))
226
+ return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-fee-not-enough");
227
+ txfee = txfee_aux;
204
228
  }
205
-
206
- txfee = txfee_aux;
207
229
  return true;
208
230
  }
231
+
232
+ CAmount GetMinFee(const CTransaction& tx, unsigned int nTimeTx)
233
+ {
234
+ size_t nBytes = ::GetSerializeSize(tx, SER_NETWORK, PROTOCOL_VERSION);
235
+ return GetMinFee(nBytes, nTimeTx);
236
+ }
237
+
238
+ CAmount GetMinFee(size_t nBytes, uint32_t nTime)
239
+ {
240
+ CAmount nMinFee;
241
+ if (IsProtocolV07(nTime) || !nTime) // RFC-0007
242
+ nMinFee = (nBytes < 100) ? MIN_TX_FEE : (CAmount)(nBytes * (PERKB_TX_FEE / 1000));
243
+ else
244
+ nMinFee = (1 + (CAmount)nBytes / 1000) * PERKB_TX_FEE;
245
+
246
+ if (!MoneyRange(nMinFee))
247
+ nMinFee = MAX_MONEY;
248
+ return nMinFee;
249
+ }
src/consensus/tx_verify.h CHANGED
@@ -18,13 +18,14 @@ class TxValidationState;
18
18
  /** Transaction validation functions */
19
19
 
20
20
  namespace Consensus {
21
+ struct Params;
21
22
  /**
22
23
  * Check whether all inputs of this transaction are valid (no double spends and amounts)
23
24
  * This does not modify the UTXO set. This does not check scripts and sigs.
24
25
  * @param[out] txfee Set to the transaction fee if successful.
25
26
  * Preconditions: tx.IsCoinBase() is false.
26
27
  */
27
- [[nodiscard]] bool CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee);
28
+ bool CheckTxInputs(const CTransaction& tx, TxValidationState& state, const CCoinsViewCache& inputs, int nSpendHeight, CAmount& txfee, const Consensus::Params& params, unsigned int nTimeTx, uint64_t nMoneySupply=0);
28
29
  } // namespace Consensus
29
30
 
30
31
  /** Auxiliary functions for transaction validation (ideally should not be exposed) */
@@ -75,4 +76,8 @@ bool EvaluateSequenceLocks(const CBlockIndex& block, std::pair<int, int64_t> loc
75
76
  */
76
77
  bool SequenceLocks(const CTransaction &tx, int flags, std::vector<int>& prevHeights, const CBlockIndex& block);
77
78
 
79
+ // peercoin: minimum fee for transaction to be accepted in a blockchain.
80
+ CAmount GetMinFee(const CTransaction& tx, unsigned int nTimeTx);
81
+ CAmount GetMinFee(size_t nBytes, uint32_t nTime);
82
+
78
83
  #endif // BITCOIN_CONSENSUS_TX_VERIFY_H
src/core_write.cpp CHANGED
@@ -29,7 +29,7 @@ UniValue ValueFromAmount(const CAmount amount)
29
29
  remainder = -remainder;
30
30
  }
31
31
  return UniValue(UniValue::VNUM,
32
- strprintf("%s%d.%08d", amount < 0 ? "-" : "", quotient, remainder));
32
+ strprintf("%s%d.%06d", amount < 0 ? "-" : "", quotient, remainder));
33
33
  }
34
34
 
35
35
  std::string FormatScript(const CScript& script)
@@ -174,6 +174,7 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
174
174
  // Transaction version is actually unsigned in consensus checks, just signed in memory,
175
175
  // so cast to unsigned before giving it to the user.
176
176
  entry.pushKV("version", static_cast<int64_t>(static_cast<uint32_t>(tx.nVersion)));
177
+ entry.pushKV("time", (int64_t)tx.nTime);
177
178
  entry.pushKV("size", (int)::GetSerializeSize(tx, PROTOCOL_VERSION));
178
179
  entry.pushKV("vsize", (GetTransactionWeight(tx) + WITNESS_SCALE_FACTOR - 1) / WITNESS_SCALE_FACTOR);
179
180
  entry.pushKV("weight", GetTransactionWeight(tx));
@@ -252,8 +253,10 @@ void TxToUniv(const CTransaction& tx, const uint256& hashBlock, UniValue& entry,
252
253
 
253
254
  if (have_undo) {
254
255
  const CAmount fee = amt_total_in - amt_total_out;
255
- CHECK_NONFATAL(MoneyRange(fee));
256
- entry.pushKV("fee", ValueFromAmount(fee));
256
+ if (fee > 0)
257
+ entry.pushKV("fee", ValueFromAmount(fee));
258
+ else
259
+ entry.pushKV("reward", ValueFromAmount(-fee));
257
260
  }
258
261
 
259
262
  if (!hashBlock.IsNull())
src/deploymentstatus.cpp DELETED
@@ -1,34 +0,0 @@
1
- // Copyright (c) 2020-2021 The Bitcoin Core developers
2
- // Distributed under the MIT software license, see the accompanying
3
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
-
5
- #include <deploymentstatus.h>
6
-
7
- #include <consensus/params.h>
8
- #include <versionbits.h>
9
-
10
- #include <type_traits>
11
-
12
- VersionBitsCache g_versionbitscache;
13
-
14
- /* Basic sanity checking for BuriedDeployment/DeploymentPos enums and
15
- * ValidDeployment check */
16
-
17
- static_assert(ValidDeployment(Consensus::DEPLOYMENT_TESTDUMMY), "sanity check of DeploymentPos failed (TESTDUMMY not valid)");
18
- static_assert(!ValidDeployment(Consensus::MAX_VERSION_BITS_DEPLOYMENTS), "sanity check of DeploymentPos failed (MAX value considered valid)");
19
- static_assert(!ValidDeployment(static_cast<Consensus::BuriedDeployment>(Consensus::DEPLOYMENT_TESTDUMMY)), "sanity check of BuriedDeployment failed (overlaps with DeploymentPos)");
20
-
21
- /* ValidDeployment only checks upper bounds for ensuring validity.
22
- * This checks that the lowest possible value or the type is also a
23
- * (specific) valid deployment so that lower bounds don't need to be checked.
24
- */
25
-
26
- template<typename T, T x>
27
- static constexpr bool is_minimum()
28
- {
29
- using U = typename std::underlying_type<T>::type;
30
- return x == std::numeric_limits<U>::min();
31
- }
32
-
33
- static_assert(is_minimum<Consensus::BuriedDeployment, Consensus::DEPLOYMENT_HEIGHTINCB>(), "heightincb is not minimum value for BuriedDeployment");
34
- static_assert(is_minimum<Consensus::DeploymentPos, Consensus::DEPLOYMENT_TESTDUMMY>(), "testdummy is not minimum value for DeploymentPos");
src/deploymentstatus.h DELETED
@@ -1,55 +0,0 @@
1
- // Copyright (c) 2020-2021 The Bitcoin Core developers
2
- // Distributed under the MIT software license, see the accompanying
3
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
-
5
- #ifndef BITCOIN_DEPLOYMENTSTATUS_H
6
- #define BITCOIN_DEPLOYMENTSTATUS_H
7
-
8
- #include <chain.h>
9
- #include <versionbits.h>
10
-
11
- #include <limits>
12
-
13
- /** Global cache for versionbits deployment status */
14
- extern VersionBitsCache g_versionbitscache;
15
-
16
- /** Determine if a deployment is active for the next block */
17
- inline bool DeploymentActiveAfter(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::BuriedDeployment dep)
18
- {
19
- assert(Consensus::ValidDeployment(dep));
20
- return (pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1) >= params.DeploymentHeight(dep);
21
- }
22
-
23
- inline bool DeploymentActiveAfter(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos dep)
24
- {
25
- assert(Consensus::ValidDeployment(dep));
26
- return ThresholdState::ACTIVE == g_versionbitscache.State(pindexPrev, params, dep);
27
- }
28
-
29
- /** Determine if a deployment is active for this block */
30
- inline bool DeploymentActiveAt(const CBlockIndex& index, const Consensus::Params& params, Consensus::BuriedDeployment dep)
31
- {
32
- assert(Consensus::ValidDeployment(dep));
33
- return index.nHeight >= params.DeploymentHeight(dep);
34
- }
35
-
36
- inline bool DeploymentActiveAt(const CBlockIndex& index, const Consensus::Params& params, Consensus::DeploymentPos dep)
37
- {
38
- assert(Consensus::ValidDeployment(dep));
39
- return DeploymentActiveAfter(index.pprev, params, dep);
40
- }
41
-
42
- /** Determine if a deployment is enabled (can ever be active) */
43
- inline bool DeploymentEnabled(const Consensus::Params& params, Consensus::BuriedDeployment dep)
44
- {
45
- assert(Consensus::ValidDeployment(dep));
46
- return params.DeploymentHeight(dep) != std::numeric_limits<int>::max();
47
- }
48
-
49
- inline bool DeploymentEnabled(const Consensus::Params& params, Consensus::DeploymentPos dep)
50
- {
51
- assert(Consensus::ValidDeployment(dep));
52
- return params.vDeployments[dep].nStartTime != Consensus::BIP9Deployment::NEVER_ACTIVE;
53
- }
54
-
55
- #endif // BITCOIN_DEPLOYMENTSTATUS_H
src/dummywallet.cpp CHANGED
@@ -35,7 +35,6 @@ void DummyWalletInit::AddWalletOptions(ArgsManager& argsman) const
35
35
  "-fallbackfee=<amt>",
36
36
  "-keypool=<n>",
37
37
  "-maxapsfee=<n>",
38
- "-maxtxfee=<amt>",
39
38
  "-mintxfee=<amt>",
40
39
  "-paytxfee=<amt>",
41
40
  "-signer=<cmd>",
@@ -45,7 +44,6 @@ void DummyWalletInit::AddWalletOptions(ArgsManager& argsman) const
45
44
  "-walletbroadcast",
46
45
  "-walletdir=<dir>",
47
46
  "-walletnotify=<cmd>",
48
- "-walletrbf",
49
47
  "-dblogsize=<n>",
50
48
  "-flushwallet",
51
49
  "-privdb",
src/gen_ecmult_gen_static_prec_table.c ADDED
@@ -0,0 +1,83 @@
1
+ /***********************************************************************
2
+ * Copyright (c) 2013, 2014, 2015 Thomas Daede, Cory Fields *
3
+ * Distributed under the MIT software license, see the accompanying *
4
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php.*
5
+ ***********************************************************************/
6
+
7
+ #include <inttypes.h>
8
+ #include <stdio.h>
9
+
10
+ #include "../include/secp256k1.h"
11
+ #include "assumptions.h"
12
+ #include "util.h"
13
+ #include "group.h"
14
+ #include "ecmult_gen.h"
15
+ #include "ecmult_gen_prec_impl.h"
16
+
17
+ int main(int argc, char **argv) {
18
+ const char outfile[] = "src/ecmult_gen_static_prec_table.h";
19
+ FILE* fp;
20
+ int bits;
21
+
22
+ (void)argc;
23
+ (void)argv;
24
+
25
+ fp = fopen(outfile, "w");
26
+ if (fp == NULL) {
27
+ fprintf(stderr, "Could not open %s for writing!\n", outfile);
28
+ return -1;
29
+ }
30
+
31
+ fprintf(fp, "/* This file was automatically generated by gen_ecmult_gen_static_prec_table. */\n");
32
+ fprintf(fp, "/* See ecmult_gen_impl.h for details about the contents of this file. */\n");
33
+ fprintf(fp, "#ifndef SECP256K1_ECMULT_GEN_STATIC_PREC_TABLE_H\n");
34
+ fprintf(fp, "#define SECP256K1_ECMULT_GEN_STATIC_PREC_TABLE_H\n");
35
+
36
+ fprintf(fp, "#include \"group.h\"\n");
37
+
38
+ fprintf(fp, "#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) "
39
+ "SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,"
40
+ "0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u)\n");
41
+
42
+ fprintf(fp, "#ifdef EXHAUSTIVE_TEST_ORDER\n");
43
+ fprintf(fp, "static secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[ECMULT_GEN_PREC_N(ECMULT_GEN_PREC_BITS)][ECMULT_GEN_PREC_G(ECMULT_GEN_PREC_BITS)];\n");
44
+ fprintf(fp, "#else\n");
45
+ fprintf(fp, "static const secp256k1_ge_storage secp256k1_ecmult_gen_prec_table[ECMULT_GEN_PREC_N(ECMULT_GEN_PREC_BITS)][ECMULT_GEN_PREC_G(ECMULT_GEN_PREC_BITS)] = {\n");
46
+
47
+ for (bits = 2; bits <= 8; bits *= 2) {
48
+ int g = ECMULT_GEN_PREC_G(bits);
49
+ int n = ECMULT_GEN_PREC_N(bits);
50
+ int inner, outer;
51
+
52
+ secp256k1_ge_storage* table = checked_malloc(&default_error_callback, n * g * sizeof(secp256k1_ge_storage));
53
+ secp256k1_ecmult_gen_create_prec_table(table, &secp256k1_ge_const_g, bits);
54
+
55
+ fprintf(fp, "#if ECMULT_GEN_PREC_BITS == %d\n", bits);
56
+ for(outer = 0; outer != n; outer++) {
57
+ fprintf(fp,"{");
58
+ for(inner = 0; inner != g; inner++) {
59
+ fprintf(fp, "S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32
60
+ ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")",
61
+ SECP256K1_GE_STORAGE_CONST_GET(table[outer * g + inner]));
62
+ if (inner != g - 1) {
63
+ fprintf(fp,",\n");
64
+ }
65
+ }
66
+ if (outer != n - 1) {
67
+ fprintf(fp,"},\n");
68
+ } else {
69
+ fprintf(fp,"}\n");
70
+ }
71
+ }
72
+ fprintf(fp, "#endif\n");
73
+ free(table);
74
+ }
75
+
76
+ fprintf(fp, "};\n");
77
+ fprintf(fp, "#endif /* EXHAUSTIVE_TEST_ORDER */\n");
78
+ fprintf(fp, "#undef SC\n");
79
+ fprintf(fp, "#endif /* SECP256K1_ECMULT_GEN_STATIC_PREC_TABLE_H */\n");
80
+ fclose(fp);
81
+
82
+ return 0;
83
+ }
src/gen_ecmult_static_pre_g.c ADDED
@@ -0,0 +1,131 @@
1
+ /*****************************************************************************************************
2
+ * Copyright (c) 2013, 2014, 2017, 2021 Pieter Wuille, Andrew Poelstra, Jonas Nick, Russell O'Connor *
3
+ * Distributed under the MIT software license, see the accompanying *
4
+ * file COPYING or https://www.opensource.org/licenses/mit-license.php. *
5
+ *****************************************************************************************************/
6
+
7
+ #include <inttypes.h>
8
+ #include <stdio.h>
9
+
10
+ /* Autotools creates libsecp256k1-config.h, of which ECMULT_WINDOW_SIZE is needed.
11
+ ifndef guard so downstream users can define their own if they do not use autotools. */
12
+ #if !defined(ECMULT_WINDOW_SIZE)
13
+ #include "libsecp256k1-config.h"
14
+ #endif
15
+
16
+ #include "../include/secp256k1.h"
17
+ #include "assumptions.h"
18
+ #include "util.h"
19
+ #include "field_impl.h"
20
+ #include "group_impl.h"
21
+ #include "ecmult.h"
22
+
23
+ void print_table(FILE *fp, const char *name, int window_g, const secp256k1_gej *gen, int with_conditionals) {
24
+ static secp256k1_gej gj;
25
+ static secp256k1_ge ge, dgen;
26
+ static secp256k1_ge_storage ges;
27
+ int j;
28
+ int i;
29
+
30
+ gj = *gen;
31
+ secp256k1_ge_set_gej_var(&ge, &gj);
32
+ secp256k1_ge_to_storage(&ges, &ge);
33
+
34
+ fprintf(fp, "static const secp256k1_ge_storage %s[ECMULT_TABLE_SIZE(WINDOW_G)] = {\n", name);
35
+ fprintf(fp, " S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32
36
+ ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")\n",
37
+ SECP256K1_GE_STORAGE_CONST_GET(ges));
38
+
39
+ secp256k1_gej_double_var(&gj, gen, NULL);
40
+ secp256k1_ge_set_gej_var(&dgen, &gj);
41
+
42
+ j = 1;
43
+ for(i = 3; i <= window_g; ++i) {
44
+ if (with_conditionals) {
45
+ fprintf(fp, "#if ECMULT_TABLE_SIZE(WINDOW_G) > %ld\n", ECMULT_TABLE_SIZE(i-1));
46
+ }
47
+ for(;j < ECMULT_TABLE_SIZE(i); ++j) {
48
+ secp256k1_gej_set_ge(&gj, &ge);
49
+ secp256k1_gej_add_ge_var(&gj, &gj, &dgen, NULL);
50
+ secp256k1_ge_set_gej_var(&ge, &gj);
51
+ secp256k1_ge_to_storage(&ges, &ge);
52
+
53
+ fprintf(fp, ",S(%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32
54
+ ",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32",%"PRIx32")\n",
55
+ SECP256K1_GE_STORAGE_CONST_GET(ges));
56
+ }
57
+ if (with_conditionals) {
58
+ fprintf(fp, "#endif\n");
59
+ }
60
+ }
61
+ fprintf(fp, "};\n");
62
+ }
63
+
64
+ void print_two_tables(FILE *fp, int window_g, const secp256k1_ge *g, int with_conditionals) {
65
+ secp256k1_gej gj;
66
+ int i;
67
+
68
+ secp256k1_gej_set_ge(&gj, g);
69
+ print_table(fp, "secp256k1_pre_g", window_g, &gj, with_conditionals);
70
+ for (i = 0; i < 128; ++i) {
71
+ secp256k1_gej_double_var(&gj, &gj, NULL);
72
+ }
73
+ print_table(fp, "secp256k1_pre_g_128", window_g, &gj, with_conditionals);
74
+ }
75
+
76
+ int main(void) {
77
+ const secp256k1_ge g = SECP256K1_G;
78
+ const secp256k1_ge g_13 = SECP256K1_G_ORDER_13;
79
+ const secp256k1_ge g_199 = SECP256K1_G_ORDER_199;
80
+ const int window_g_13 = 4;
81
+ const int window_g_199 = 8;
82
+ FILE* fp;
83
+
84
+ fp = fopen("src/ecmult_static_pre_g.h","w");
85
+ if (fp == NULL) {
86
+ fprintf(stderr, "Could not open src/ecmult_static_pre_g.h for writing!\n");
87
+ return -1;
88
+ }
89
+
90
+ fprintf(fp, "/* This file was automatically generated by gen_ecmult_static_pre_g. */\n");
91
+ fprintf(fp, "/* This file contains an array secp256k1_pre_g with odd multiples of the base point G and\n");
92
+ fprintf(fp, " * an array secp256k1_pre_g_128 with odd multiples of 2^128*G for accelerating the computation of a*P + b*G.\n");
93
+ fprintf(fp, " */\n");
94
+ fprintf(fp, "#ifndef SECP256K1_ECMULT_STATIC_PRE_G_H\n");
95
+ fprintf(fp, "#define SECP256K1_ECMULT_STATIC_PRE_G_H\n");
96
+ fprintf(fp, "#include \"group.h\"\n");
97
+ fprintf(fp, "#ifdef S\n");
98
+ fprintf(fp, " #error macro identifier S already in use.\n");
99
+ fprintf(fp, "#endif\n");
100
+ fprintf(fp, "#define S(a,b,c,d,e,f,g,h,i,j,k,l,m,n,o,p) "
101
+ "SECP256K1_GE_STORAGE_CONST(0x##a##u,0x##b##u,0x##c##u,0x##d##u,0x##e##u,0x##f##u,0x##g##u,"
102
+ "0x##h##u,0x##i##u,0x##j##u,0x##k##u,0x##l##u,0x##m##u,0x##n##u,0x##o##u,0x##p##u)\n");
103
+ fprintf(fp, "#if ECMULT_TABLE_SIZE(ECMULT_WINDOW_SIZE) > %ld\n", ECMULT_TABLE_SIZE(ECMULT_WINDOW_SIZE));
104
+ fprintf(fp, " #error configuration mismatch, invalid ECMULT_WINDOW_SIZE. Try deleting ecmult_static_pre_g.h before the build.\n");
105
+ fprintf(fp, "#endif\n");
106
+ fprintf(fp, "#if defined(EXHAUSTIVE_TEST_ORDER)\n");
107
+ fprintf(fp, "#if EXHAUSTIVE_TEST_ORDER == 13\n");
108
+ fprintf(fp, "#define WINDOW_G %d\n", window_g_13);
109
+
110
+ print_two_tables(fp, window_g_13, &g_13, 0);
111
+
112
+ fprintf(fp, "#elif EXHAUSTIVE_TEST_ORDER == 199\n");
113
+ fprintf(fp, "#define WINDOW_G %d\n", window_g_199);
114
+
115
+ print_two_tables(fp, window_g_199, &g_199, 0);
116
+
117
+ fprintf(fp, "#else\n");
118
+ fprintf(fp, " #error No known generator for the specified exhaustive test group order.\n");
119
+ fprintf(fp, "#endif\n");
120
+ fprintf(fp, "#else /* !defined(EXHAUSTIVE_TEST_ORDER) */\n");
121
+ fprintf(fp, "#define WINDOW_G ECMULT_WINDOW_SIZE\n");
122
+
123
+ print_two_tables(fp, ECMULT_WINDOW_SIZE, &g, 1);
124
+
125
+ fprintf(fp, "#endif\n");
126
+ fprintf(fp, "#undef S\n");
127
+ fprintf(fp, "#endif\n");
128
+ fclose(fp);
129
+
130
+ return 0;
131
+ }
src/hash.cpp CHANGED
@@ -94,3 +94,12 @@ CHashWriter TaggedHash(const std::string& tag)
94
94
  writer << taghash << taghash;
95
95
  return writer;
96
96
  }
97
+
98
+ int32_t peercoinRandseed;
99
+ int univHash(const uint256 &x) {
100
+ int h = peercoinRandseed >> 20;
101
+ const uint32_t *p = x.GetDataPtr();
102
+ for(int i = 0; i < 8; i++)
103
+ h ^= (p[i] >> (h & 0xf)) + (peercoinRandseed >> i);
104
+ return (h + (h >> 16)) & 1023; // 2^n - 1
105
+ }
src/hash.h CHANGED
@@ -212,4 +212,7 @@ void BIP32Hash(const ChainCode &chainCode, unsigned int nChild, unsigned char he
212
212
  */
213
213
  CHashWriter TaggedHash(const std::string& tag);
214
214
 
215
+ extern int32_t peercoinRandseed;
216
+ int univHash(const uint256 &x);
217
+
215
218
  #endif // BITCOIN_HASH_H
src/index/base.cpp CHANGED
@@ -105,7 +105,7 @@ bool BaseIndex::Init()
105
105
  }
106
106
  }
107
107
  if (prune_violation) {
108
- return InitError(strprintf(Untranslated("%s best block of the index goes beyond pruned data. Please disable the index or reindex (which will download the whole blockchain again)"), GetName()));
108
+ return InitError(strprintf(Untranslated("%s best block of the index goes beyond pruned data. Please disable the index or reindex (which will download the whole blockchain again)"), GetName())); // peercoin: should never happen
109
109
  }
110
110
  }
111
111
  return true;
src/index/coinstatsindex.cpp CHANGED
@@ -112,8 +112,8 @@ CoinStatsIndex::CoinStatsIndex(size_t n_cache_size, bool f_memory, bool f_wipe)
112
112
  bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
113
113
  {
114
114
  CBlockUndo block_undo;
115
- const CAmount block_subsidy{GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
116
- m_total_subsidy += block_subsidy;
115
+ //const CAmount block_subsidy{GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
116
+ //m_total_subsidy += block_subsidy;
117
117
 
118
118
  // Ignore genesis block
119
119
  if (pindex->nHeight > 0) {
@@ -147,14 +147,14 @@ bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
147
147
 
148
148
  // Skip duplicate txid coinbase transactions (BIP30).
149
149
  if (is_bip30_block && tx->IsCoinBase()) {
150
- m_total_unspendable_amount += block_subsidy;
151
- m_total_unspendables_bip30 += block_subsidy;
150
+ //m_total_unspendable_amount += block_subsidy;
151
+ //m_total_unspendables_bip30 += block_subsidy;
152
152
  continue;
153
153
  }
154
154
 
155
155
  for (uint32_t j = 0; j < tx->vout.size(); ++j) {
156
156
  const CTxOut& out{tx->vout[j]};
157
- Coin coin{out, pindex->nHeight, tx->IsCoinBase()};
157
+ Coin coin{out, pindex->nHeight, tx->IsCoinBase(), tx->IsCoinStake(), (int)tx->nTime};
158
158
  COutPoint outpoint{tx->GetHash(), j};
159
159
 
160
160
  // Skip unspendable coins
@@ -197,17 +197,17 @@ bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
197
197
  }
198
198
  } else {
199
199
  // genesis block
200
- m_total_unspendable_amount += block_subsidy;
201
- m_total_unspendables_genesis_block += block_subsidy;
200
+ //m_total_unspendable_amount += block_subsidy;
201
+ //m_total_unspendables_genesis_block += block_subsidy;
202
202
  }
203
203
 
204
204
  // If spent prevouts + block subsidy are still a higher amount than
205
205
  // new outputs + coinbase + current unspendable amount this means
206
206
  // the miner did not claim the full block reward. Unclaimed block
207
207
  // rewards are also unspendable.
208
- const CAmount unclaimed_rewards{(m_total_prevout_spent_amount + m_total_subsidy) - (m_total_new_outputs_ex_coinbase_amount + m_total_coinbase_amount + m_total_unspendable_amount)};
209
- m_total_unspendable_amount += unclaimed_rewards;
210
- m_total_unspendables_unclaimed_rewards += unclaimed_rewards;
208
+ //const CAmount unclaimed_rewards{(m_total_prevout_spent_amount + m_total_subsidy) - (m_total_new_outputs_ex_coinbase_amount + m_total_coinbase_amount + m_total_unspendable_amount)};
209
+ //m_total_unspendable_amount += unclaimed_rewards;
210
+ //m_total_unspendables_unclaimed_rewards += unclaimed_rewards;
211
211
 
212
212
  std::pair<uint256, DBVal> value;
213
213
  value.first = pindex->GetBlockHash();
@@ -215,14 +215,14 @@ bool CoinStatsIndex::WriteBlock(const CBlock& block, const CBlockIndex* pindex)
215
215
  value.second.bogo_size = m_bogo_size;
216
216
  value.second.total_amount = m_total_amount;
217
217
  value.second.total_subsidy = m_total_subsidy;
218
- value.second.total_unspendable_amount = m_total_unspendable_amount;
218
+ //value.second.total_unspendable_amount = m_total_unspendable_amount;
219
219
  value.second.total_prevout_spent_amount = m_total_prevout_spent_amount;
220
220
  value.second.total_new_outputs_ex_coinbase_amount = m_total_new_outputs_ex_coinbase_amount;
221
221
  value.second.total_coinbase_amount = m_total_coinbase_amount;
222
- value.second.total_unspendables_genesis_block = m_total_unspendables_genesis_block;
223
- value.second.total_unspendables_bip30 = m_total_unspendables_bip30;
222
+ //value.second.total_unspendables_genesis_block = m_total_unspendables_genesis_block;
223
+ //value.second.total_unspendables_bip30 = m_total_unspendables_bip30;
224
224
  value.second.total_unspendables_scripts = m_total_unspendables_scripts;
225
- value.second.total_unspendables_unclaimed_rewards = m_total_unspendables_unclaimed_rewards;
225
+ //value.second.total_unspendables_unclaimed_rewards = m_total_unspendables_unclaimed_rewards;
226
226
 
227
227
  uint256 out;
228
228
  m_muhash.Finalize(out);
@@ -374,15 +374,15 @@ bool CoinStatsIndex::Init()
374
374
  m_transaction_output_count = entry.transaction_output_count;
375
375
  m_bogo_size = entry.bogo_size;
376
376
  m_total_amount = entry.total_amount;
377
- m_total_subsidy = entry.total_subsidy;
378
- m_total_unspendable_amount = entry.total_unspendable_amount;
377
+ //m_total_subsidy = entry.total_subsidy;
378
+ //m_total_unspendable_amount = entry.total_unspendable_amount;
379
379
  m_total_prevout_spent_amount = entry.total_prevout_spent_amount;
380
380
  m_total_new_outputs_ex_coinbase_amount = entry.total_new_outputs_ex_coinbase_amount;
381
381
  m_total_coinbase_amount = entry.total_coinbase_amount;
382
- m_total_unspendables_genesis_block = entry.total_unspendables_genesis_block;
383
- m_total_unspendables_bip30 = entry.total_unspendables_bip30;
382
+ //m_total_unspendables_genesis_block = entry.total_unspendables_genesis_block;
383
+ //m_total_unspendables_bip30 = entry.total_unspendables_bip30;
384
384
  m_total_unspendables_scripts = entry.total_unspendables_scripts;
385
- m_total_unspendables_unclaimed_rewards = entry.total_unspendables_unclaimed_rewards;
385
+ //m_total_unspendables_unclaimed_rewards = entry.total_unspendables_unclaimed_rewards;
386
386
  }
387
387
 
388
388
  return true;
@@ -394,8 +394,8 @@ bool CoinStatsIndex::ReverseBlock(const CBlock& block, const CBlockIndex* pindex
394
394
  CBlockUndo block_undo;
395
395
  std::pair<uint256, DBVal> read_out;
396
396
 
397
- const CAmount block_subsidy{GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
398
- m_total_subsidy -= block_subsidy;
397
+ //const CAmount block_subsidy{GetBlockSubsidy(pindex->nHeight, Params().GetConsensus())};
398
+ //m_total_subsidy -= block_subsidy;
399
399
 
400
400
  // Ignore genesis block
401
401
  if (pindex->nHeight > 0) {
@@ -426,7 +426,7 @@ bool CoinStatsIndex::ReverseBlock(const CBlock& block, const CBlockIndex* pindex
426
426
  for (uint32_t j = 0; j < tx->vout.size(); ++j) {
427
427
  const CTxOut& out{tx->vout[j]};
428
428
  COutPoint outpoint{tx->GetHash(), j};
429
- Coin coin{out, pindex->nHeight, tx->IsCoinBase()};
429
+ Coin coin{out, pindex->nHeight, tx->IsCoinBase(), tx->IsCoinStake(), (int)tx->nTime};
430
430
 
431
431
  // Skip unspendable coins
432
432
  if (coin.out.scriptPubKey.IsUnspendable()) {
src/index/txindex.cpp CHANGED
@@ -100,3 +100,8 @@ bool TxIndex::FindTx(const uint256& tx_hash, uint256& block_hash, CTransactionRe
100
100
  block_hash = header.GetHash();
101
101
  return true;
102
102
  }
103
+
104
+ bool TxIndex::FindTxPosition(const uint256& txid, CDiskTxPos& pos) const
105
+ {
106
+ return m_db->ReadTxPos(txid, pos);
107
+ }
src/index/txindex.h CHANGED
@@ -6,6 +6,8 @@
6
6
  #define BITCOIN_INDEX_TXINDEX_H
7
7
 
8
8
  #include <index/base.h>
9
+ #include <index/disktxpos.h>
10
+ #include <primitives/block.h>
9
11
 
10
12
  /**
11
13
  * TxIndex is used to look up transactions included in the blockchain by hash.
@@ -41,6 +43,9 @@ public:
41
43
  /// @param[out] tx The transaction itself.
42
44
  /// @return true if transaction is found, false otherwise
43
45
  bool FindTx(const uint256& tx_hash, uint256& block_hash, CTransactionRef& tx) const;
46
+
47
+ bool FindTxPosition(const uint256& txid, CDiskTxPos& pos) const;
48
+ std::map<uint256,std::pair<CBlockHeader,CTransactionRef>> cachedTxs;
44
49
  };
45
50
 
46
51
  /// The global transaction index, used in GetTransaction. May be null.
src/init.cpp CHANGED
@@ -16,7 +16,6 @@
16
16
  #include <chainparams.h>
17
17
  #include <compat/sanity.h>
18
18
  #include <consensus/amount.h>
19
- #include <deploymentstatus.h>
20
19
  #include <fs.h>
21
20
  #include <hash.h>
22
21
  #include <httprpc.h>
@@ -39,8 +38,6 @@
39
38
  #include <node/context.h>
40
39
  #include <node/miner.h>
41
40
  #include <node/ui_interface.h>
42
- #include <policy/feerate.h>
43
- #include <policy/fees.h>
44
41
  #include <policy/policy.h>
45
42
  #include <policy/settings.h>
46
43
  #include <protocol.h>
@@ -62,13 +59,13 @@
62
59
  #include <util/check.h>
63
60
  #include <util/moneystr.h>
64
61
  #include <util/strencodings.h>
65
- #include <util/string.h>
66
62
  #include <util/syscall_sandbox.h>
67
63
  #include <util/system.h>
68
64
  #include <util/thread.h>
69
65
  #include <util/threadnames.h>
70
66
  #include <util/translation.h>
71
67
  #include <validation.h>
68
+
72
69
  #include <validationinterface.h>
73
70
  #include <walletinitinterface.h>
74
71
 
@@ -102,17 +99,14 @@ using node::CacheSizes;
102
99
  using node::CalculateCacheSizes;
103
100
  using node::ChainstateLoadVerifyError;
104
101
  using node::ChainstateLoadingError;
105
- using node::CleanupBlockRevFiles;
106
102
  using node::DEFAULT_PRINTPRIORITY;
107
103
  using node::DEFAULT_STOPAFTERBLOCKIMPORT;
108
104
  using node::LoadChainstate;
109
105
  using node::NodeContext;
110
106
  using node::ThreadImport;
111
107
  using node::VerifyLoadedChainstate;
112
- using node::fHavePruned;
113
- using node::fPruneMode;
114
108
  using node::fReindex;
115
- using node::nPruneTarget;
109
+ using interfaces::WalletLoader;
116
110
 
117
111
  static const bool DEFAULT_PROXYRANDOMIZE = true;
118
112
  static const bool DEFAULT_REST_ENABLE = false;
@@ -131,7 +125,9 @@ static const char* DEFAULT_ASMAP_FILENAME="ip_asn.map";
131
125
  /**
132
126
  * The PID file facilities.
133
127
  */
134
- static const char* BITCOIN_PID_FILENAME = "bitcoind.pid";
128
+ static const char* BITCOIN_PID_FILENAME = "peercoind.pid";
129
+
130
+ static std::shared_ptr<CWallet> walletTmp;
135
131
 
136
132
  static fs::path GetPidFile(const ArgsManager& args)
137
133
  {
@@ -245,8 +241,6 @@ void Shutdown(NodeContext& node)
245
241
  DumpMempool(*node.mempool);
246
242
  }
247
243
 
248
- // Drop transactions we were still watching, and record fee estimations.
249
- if (node.fee_estimator) node.fee_estimator->Flush();
250
244
 
251
245
  // FlushStateToDisk generates a ChainStateFlushed callback, which we should avoid missing
252
246
  if (node.chainman) {
@@ -306,7 +300,6 @@ void Shutdown(NodeContext& node)
306
300
  GetMainSignals().UnregisterBackgroundSignalScheduler();
307
301
  init::UnsetGlobals();
308
302
  node.mempool.reset();
309
- node.fee_estimator.reset();
310
303
  node.chainman.reset();
311
304
  node.scheduler.reset();
312
305
 
@@ -420,9 +413,6 @@ void SetupServerArgs(ArgsManager& argsman)
420
413
  -GetNumCores(), MAX_SCRIPTCHECK_THREADS, DEFAULT_SCRIPTCHECK_THREADS), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
421
414
  argsman.AddArg("-persistmempool", strprintf("Whether to save the mempool on shutdown and load on restart (default: %u)", DEFAULT_PERSIST_MEMPOOL), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
422
415
  argsman.AddArg("-pid=<file>", strprintf("Specify pid file. Relative paths will be prefixed by a net-specific datadir location. (default: %s)", BITCOIN_PID_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
423
- argsman.AddArg("-prune=<n>", strprintf("Reduce storage requirements by enabling pruning (deleting) of old blocks. This allows the pruneblockchain RPC to be called to delete specific blocks, and enables automatic pruning of old blocks if a target size in MiB is provided. This mode is incompatible with -txindex and -coinstatsindex. "
424
- "Warning: Reverting this setting requires re-downloading the entire blockchain. "
425
- "(default: 0 = disable pruning blocks, 1 = allow manual pruning via RPC, >=%u = automatically prune block files to stay under the specified target size in MiB)", MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
426
416
  argsman.AddArg("-reindex", "Rebuild chain state and block index from the blk*.dat files on disk", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
427
417
  argsman.AddArg("-reindex-chainstate", "Rebuild chain state from the currently indexed blocks. When in pruning mode or if blocks on disk might be corrupted, use full -reindex instead.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
428
418
  argsman.AddArg("-settings=<file>", strprintf("Specify path to dynamic settings data file. Can be disabled with -nosettings. File is written at runtime and not meant to be edited by users (use %s instead for custom settings). Relative paths will be prefixed by datadir location. (default: %s)", BITCOIN_CONF_FILENAME, BITCOIN_SETTINGS_FILENAME), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -549,19 +539,15 @@ void SetupServerArgs(ArgsManager& argsman)
549
539
  SetupChainParamsBaseOptions(argsman);
550
540
 
551
541
  argsman.AddArg("-acceptnonstdtxn", strprintf("Relay and mine \"non-standard\" transactions (%sdefault: %u)", "testnet/regtest only; ", !testnetChainParams->RequireStandard()), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
552
- argsman.AddArg("-incrementalrelayfee=<amt>", strprintf("Fee rate (in %s/kvB) used to define cost of relay, used for mempool limiting and BIP 125 replacement. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_INCREMENTAL_RELAY_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
553
- argsman.AddArg("-dustrelayfee=<amt>", strprintf("Fee rate (in %s/kvB) used to define dust, the value of an output such that it will cost more than its value in fees at this fee rate to spend it. (default: %s)", CURRENCY_UNIT, FormatMoney(DUST_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::NODE_RELAY);
554
542
  argsman.AddArg("-bytespersigop", strprintf("Equivalent bytes per sigop in transactions for relay and mining (default: %u)", DEFAULT_BYTES_PER_SIGOP), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
555
543
  argsman.AddArg("-datacarrier", strprintf("Relay and mine data carrier transactions (default: %u)", DEFAULT_ACCEPT_DATACARRIER), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
556
544
  argsman.AddArg("-datacarriersize", strprintf("Maximum size of data in data carrier transactions we relay and mine (default: %u)", MAX_OP_RETURN_RELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
557
- argsman.AddArg("-minrelaytxfee=<amt>", strprintf("Fees (in %s/kvB) smaller than this are considered zero fee for relaying, mining and transaction creation (default: %s)",
558
- CURRENCY_UNIT, FormatMoney(DEFAULT_MIN_RELAY_TX_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
545
+
559
546
  argsman.AddArg("-whitelistforcerelay", strprintf("Add 'forcerelay' permission to whitelisted inbound peers with default permissions. This will relay transactions even if the transactions were already in the mempool. (default: %d)", DEFAULT_WHITELISTFORCERELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
560
547
  argsman.AddArg("-whitelistrelay", strprintf("Add 'relay' permission to whitelisted inbound peers with default permissions. This will accept relayed transactions even when not relaying transactions (default: %d)", DEFAULT_WHITELISTRELAY), ArgsManager::ALLOW_ANY, OptionsCategory::NODE_RELAY);
561
548
 
562
549
 
563
550
  argsman.AddArg("-blockmaxweight=<n>", strprintf("Set maximum BIP141 block weight (default: %d)", DEFAULT_BLOCK_MAX_WEIGHT), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION);
564
- argsman.AddArg("-blockmintxfee=<amt>", strprintf("Set lowest fee rate (in %s/kvB) for transactions to be included in block creation. (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_BLOCK_MIN_TX_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION);
565
551
  argsman.AddArg("-blockversion=<n>", "Override block version to test forking scenarios", ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::BLOCK_CREATION);
566
552
 
567
553
  argsman.AddArg("-rest", strprintf("Accept public REST requests (default: %u)", DEFAULT_REST_ENABLE), ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
@@ -579,6 +565,7 @@ void SetupServerArgs(ArgsManager& argsman)
579
565
  argsman.AddArg("-rpcwhitelistdefault", "Sets default behavior for rpc whitelisting. Unless rpcwhitelistdefault is set to 0, if any -rpcwhitelist is set, the rpc server acts as if all rpc users are subject to empty-unless-otherwise-specified whitelists. If rpcwhitelistdefault is set to 1 and no -rpcwhitelist is set, rpc server acts as if all rpc users are subject to empty whitelists.", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
580
566
  argsman.AddArg("-rpcworkqueue=<n>", strprintf("Set the depth of the work queue to service RPC calls (default: %d)", DEFAULT_HTTP_WORKQUEUE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::RPC);
581
567
  argsman.AddArg("-server", "Accept command line and JSON-RPC commands", ArgsManager::ALLOW_ANY, OptionsCategory::RPC);
568
+ gArgs.AddArg("-nominting", "Disable minting of POS blocks", ArgsManager::ALLOW_ANY, OptionsCategory::BLOCK_CREATION);
582
569
 
583
570
  #if HAVE_DECL_FORK
584
571
  argsman.AddArg("-daemon", strprintf("Run in the background as a daemon and accept commands (default: %d)", DEFAULT_DAEMON), ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
@@ -592,6 +579,15 @@ void SetupServerArgs(ArgsManager& argsman)
592
579
  argsman.AddArg("-sandbox=<mode>", "Use the experimental syscall sandbox in the specified mode (-sandbox=log-and-abort or -sandbox=abort). Allow only expected syscalls to be used by bitcoind. Note that this is an experimental new feature that may cause bitcoind to exit or crash unexpectedly: use with caution. In the \"log-and-abort\" mode the invocation of an unexpected syscall results in a debug handler being invoked which will log the incident and terminate the program (without executing the unexpected syscall). In the \"abort\" mode the invocation of an unexpected syscall results in the entire process being killed immediately by the kernel without executing the unexpected syscall.", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
593
580
  #endif // USE_SYSCALL_SANDBOX
594
581
 
582
+ // peercoin parameters
583
+ gArgs.AddArg("-printstakemodifier", "Print stakemodifier selection parameters if debug is enabled", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
584
+ gArgs.AddArg("-printcoinstake", "Print coinstake if debug is enabled", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
585
+ gArgs.AddArg("-printcoinage", "Print coinage if debug is enabled", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
586
+ gArgs.AddArg("-printcreation", "Print coin creation if debug is enabled", ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
587
+
588
+ gArgs.AddArg("-reservebalance=<amt>", "Reserve this many coins", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
589
+ gArgs.AddArg("-minting", "Enable minting (default: true)", ArgsManager::ALLOW_ANY, OptionsCategory::OPTIONS);
590
+
595
591
  // Add the hidden options
596
592
  argsman.AddHiddenArgs(hidden_args);
597
593
  }
@@ -853,14 +849,6 @@ bool AppInitParameterInteraction(const ArgsManager& args)
853
849
  nLocalServices = ServiceFlags(nLocalServices | NODE_COMPACT_FILTERS);
854
850
  }
855
851
 
856
- // if using block pruning, then disallow txindex and coinstatsindex
857
- if (args.GetIntArg("-prune", 0)) {
858
- if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX))
859
- return InitError(_("Prune mode is incompatible with -txindex."));
860
- if (args.GetBoolArg("-coinstatsindex", DEFAULT_COINSTATSINDEX))
861
- return InitError(_("Prune mode is incompatible with -coinstatsindex."));
862
- }
863
-
864
852
  // If -forcednsseed is set to true, ensure -dnsseed has not been set to false
865
853
  if (args.GetBoolArg("-forcednsseed", DEFAULT_FORCEDNSSEED) && !args.GetBoolArg("-dnsseed", DEFAULT_DNSSEED)){
866
854
  return InitError(_("Cannot set -forcednsseed to true when setting -dnsseed to false."));
@@ -930,33 +918,6 @@ bool AppInitParameterInteraction(const ArgsManager& args)
930
918
  int64_t nMempoolSizeMin = args.GetIntArg("-limitdescendantsize", DEFAULT_DESCENDANT_SIZE_LIMIT) * 1000 * 40;
931
919
  if (nMempoolSizeMax < 0 || nMempoolSizeMax < nMempoolSizeMin)
932
920
  return InitError(strprintf(_("-maxmempool must be at least %d MB"), std::ceil(nMempoolSizeMin / 1000000.0)));
933
- // incremental relay fee sets the minimum feerate increase necessary for BIP 125 replacement in the mempool
934
- // and the amount the mempool min fee increases above the feerate of txs evicted due to mempool limiting.
935
- if (args.IsArgSet("-incrementalrelayfee")) {
936
- if (std::optional<CAmount> inc_relay_fee = ParseMoney(args.GetArg("-incrementalrelayfee", ""))) {
937
- ::incrementalRelayFee = CFeeRate{inc_relay_fee.value()};
938
- } else {
939
- return InitError(AmountErrMsg("incrementalrelayfee", args.GetArg("-incrementalrelayfee", "")));
940
- }
941
- }
942
-
943
- // block pruning; get the amount of disk space (in MiB) to allot for block & undo files
944
- int64_t nPruneArg = args.GetIntArg("-prune", 0);
945
- if (nPruneArg < 0) {
946
- return InitError(_("Prune cannot be configured with a negative value."));
947
- }
948
- nPruneTarget = (uint64_t) nPruneArg * 1024 * 1024;
949
- if (nPruneArg == 1) { // manual pruning: -prune=1
950
- LogPrintf("Block pruning enabled. Use RPC call pruneblockchain(height) to manually prune block and undo files.\n");
951
- nPruneTarget = std::numeric_limits<uint64_t>::max();
952
- fPruneMode = true;
953
- } else if (nPruneTarget) {
954
- if (nPruneTarget < MIN_DISK_SPACE_FOR_BLOCK_FILES) {
955
- return InitError(strprintf(_("Prune configured below the minimum of %d MiB. Please use a higher number."), MIN_DISK_SPACE_FOR_BLOCK_FILES / 1024 / 1024));
956
- }
957
- LogPrintf("Prune configured to target %u MiB on disk for block and undo files.\n", nPruneTarget / 1024 / 1024);
958
- fPruneMode = true;
959
- }
960
921
 
961
922
  nConnectTimeout = args.GetIntArg("-timeout", DEFAULT_CONNECT_TIMEOUT);
962
923
  if (nConnectTimeout <= 0) {
@@ -967,38 +928,6 @@ bool AppInitParameterInteraction(const ArgsManager& args)
967
928
  if (peer_connect_timeout <= 0) {
968
929
  return InitError(Untranslated("peertimeout cannot be configured with a negative value."));
969
930
  }
970
-
971
- if (args.IsArgSet("-minrelaytxfee")) {
972
- if (std::optional<CAmount> min_relay_fee = ParseMoney(args.GetArg("-minrelaytxfee", ""))) {
973
- // High fee check is done afterward in CWallet::Create()
974
- ::minRelayTxFee = CFeeRate{min_relay_fee.value()};
975
- } else {
976
- return InitError(AmountErrMsg("minrelaytxfee", args.GetArg("-minrelaytxfee", "")));
977
- }
978
- } else if (incrementalRelayFee > ::minRelayTxFee) {
979
- // Allow only setting incrementalRelayFee to control both
980
- ::minRelayTxFee = incrementalRelayFee;
981
- LogPrintf("Increasing minrelaytxfee to %s to match incrementalrelayfee\n",::minRelayTxFee.ToString());
982
- }
983
-
984
- // Sanity check argument for min fee for including tx in block
985
- // TODO: Harmonize which arguments need sanity checking and where that happens
986
- if (args.IsArgSet("-blockmintxfee")) {
987
- if (!ParseMoney(args.GetArg("-blockmintxfee", ""))) {
988
- return InitError(AmountErrMsg("blockmintxfee", args.GetArg("-blockmintxfee", "")));
989
- }
990
- }
991
-
992
- // Feerate used to define dust. Shouldn't be changed lightly as old
993
- // implementations may inadvertently create non-standard transactions
994
- if (args.IsArgSet("-dustrelayfee")) {
995
- if (std::optional<CAmount> parsed = ParseMoney(args.GetArg("-dustrelayfee", ""))) {
996
- dustRelayFee = CFeeRate{parsed.value()};
997
- } else {
998
- return InitError(AmountErrMsg("dustrelayfee", args.GetArg("-dustrelayfee", "")));
999
- }
1000
- }
1001
-
1002
931
  fRequireStandard = !args.GetBoolArg("-acceptnonstdtxn", !chainparams.RequireStandard());
1003
932
  if (!chainparams.IsTestChain() && !fRequireStandard) {
1004
933
  return InitError(strprintf(Untranslated("acceptnonstdtxn is not currently supported for %s chain"), chainparams.NetworkIDString()));
@@ -1024,7 +953,6 @@ bool AppInitParameterInteraction(const ArgsManager& args)
1024
953
  return InitError(Untranslated("Unknown rpcserialversion requested."));
1025
954
 
1026
955
  nMaxTipAge = args.GetIntArg("-maxtipage", DEFAULT_MAX_TIP_AGE);
1027
-
1028
956
  if (args.IsArgSet("-proxy") && args.GetArg("-proxy", "").empty()) {
1029
957
  return InitError(_("No proxy server specified. Use -proxy=<ip> or -proxy=<ip:port>."));
1030
958
  }
@@ -1065,7 +993,7 @@ bool AppInitParameterInteraction(const ArgsManager& args)
1065
993
 
1066
994
  static bool LockDataDirectory(bool probeOnly)
1067
995
  {
1068
- // Make sure only a single Bitcoin process is using the data directory.
996
+ // Make sure only a single Peercoin process is using the data directory.
1069
997
  fs::path datadir = gArgs.GetDataDirNet();
1070
998
  if (!DirIsWritable(datadir)) {
1071
999
  return InitError(strprintf(_("Cannot write to data directory '%s'; check permissions."), fs::PathToString(datadir)));
@@ -1082,6 +1010,8 @@ bool AppInitSanityChecks()
1082
1010
 
1083
1011
  init::SetGlobals();
1084
1012
 
1013
+ // peercoin: init hash seed
1014
+ peercoinRandseed = GetRand(1 << 30);
1085
1015
  if (!init::SanityChecks()) {
1086
1016
  return InitError(strprintf(_("Initialization sanity check failed. %s is shutting down."), PACKAGE_NAME));
1087
1017
  }
@@ -1135,9 +1065,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1135
1065
  // Warn about relative -datadir path.
1136
1066
  if (args.IsArgSet("-datadir") && !args.GetPathArg("-datadir").is_absolute()) {
1137
1067
  LogPrintf("Warning: relative datadir option '%s' specified, which will be interpreted relative to the " /* Continued */
1138
- "current working directory '%s'. This is fragile, because if bitcoin is started in the future "
1068
+ "current working directory '%s'. This is fragile, because if peercoin is started in the future "
1139
1069
  "from a different location, it will be unable to locate the current data files. There could "
1140
- "also be data loss if bitcoin is started while in a temporary directory.\n",
1070
+ "also be data loss if peercoin is started while in a temporary directory.\n",
1141
1071
  args.GetArg("-datadir", ""), fs::PathToString(fs::current_path()));
1142
1072
  }
1143
1073
 
@@ -1262,14 +1192,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1262
1192
  assert(!node.connman);
1263
1193
  node.connman = std::make_unique<CConnman>(GetRand(std::numeric_limits<uint64_t>::max()), GetRand(std::numeric_limits<uint64_t>::max()), *node.addrman, args.GetBoolArg("-networkactive", true));
1264
1194
 
1265
- assert(!node.fee_estimator);
1266
- // Don't initialize fee estimation with old data if we don't relay transactions,
1267
- // as they would never get updated.
1268
- if (!ignores_incoming_txs) node.fee_estimator = std::make_unique<CBlockPolicyEstimator>();
1269
-
1270
1195
  assert(!node.mempool);
1271
1196
  int check_ratio = std::min<int>(std::max<int>(args.GetIntArg("-checkmempool", chainparams.DefaultConsistencyChecks() ? 1 : 0), 0), 1000000);
1272
- node.mempool = std::make_unique<CTxMemPool>(node.fee_estimator.get(), check_ratio);
1197
+ node.mempool = std::make_unique<CTxMemPool>(check_ratio);
1273
1198
 
1274
1199
  assert(!node.chainman);
1275
1200
  node.chainman = std::make_unique<ChainstateManager>();
@@ -1397,9 +1322,7 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1397
1322
  int64_t nMempoolSizeMax = args.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
1398
1323
  LogPrintf("Cache configuration:\n");
1399
1324
  LogPrintf("* Using %.1f MiB for block index database\n", cache_sizes.block_tree_db * (1.0 / 1024 / 1024));
1400
- if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
1401
- LogPrintf("* Using %.1f MiB for transaction index database\n", cache_sizes.tx_index * (1.0 / 1024 / 1024));
1402
- }
1325
+ LogPrintf("* Using %.1f MiB for transaction index database\n", cache_sizes.tx_index * (1.0 / 1024 / 1024));
1403
1326
  for (BlockFilterType filter_type : g_enabled_filter_types) {
1404
1327
  LogPrintf("* Using %.1f MiB for %s block filter index database\n",
1405
1328
  cache_sizes.filter_index * (1.0 / 1024 / 1024), BlockFilterTypeName(filter_type));
@@ -1419,7 +1342,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1419
1342
  maybe_load_error = LoadChainstate(fReset,
1420
1343
  chainman,
1421
1344
  Assert(node.mempool.get()),
1422
- fPruneMode,
1423
1345
  chainparams.GetConsensus(),
1424
1346
  fReindexChainState,
1425
1347
  cache_sizes.block_tree_db,
@@ -1446,9 +1368,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1446
1368
  // If the loaded chain has a wrong genesis, bail out immediately
1447
1369
  // (we're likely using a testnet datadir, or the other way around).
1448
1370
  return InitError(_("Incorrect or no genesis block found. Wrong datadir for network?"));
1449
- case ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX:
1450
- strLoadError = _("You need to rebuild the database using -reindex to go back to unpruned mode. This will redownload the entire blockchain");
1451
- break;
1452
1371
  case ChainstateLoadingError::ERROR_LOAD_GENESIS_BLOCK_FAILED:
1453
1372
  strLoadError = _("Error initializing block database");
1454
1373
  break;
@@ -1476,10 +1395,6 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1476
1395
  try {
1477
1396
  uiInterface.InitMessage(_("Verifying blocks…").translated);
1478
1397
  auto check_blocks = args.GetIntArg("-checkblocks", DEFAULT_CHECKBLOCKS);
1479
- if (fHavePruned && check_blocks > MIN_BLOCKS_TO_KEEP) {
1480
- LogPrintf("Prune: pruned datadir may not have more than %d blocks; only checking available blocks\n",
1481
- MIN_BLOCKS_TO_KEEP);
1482
- }
1483
1398
  maybe_verify_error = VerifyLoadedChainstate(chainman,
1484
1399
  fReset,
1485
1400
  fReindexChainState,
@@ -1540,15 +1455,13 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1540
1455
  }
1541
1456
 
1542
1457
  // ********************************************************* Step 8: start indexers
1543
- if (args.GetBoolArg("-txindex", DEFAULT_TXINDEX)) {
1544
1458
  if (const auto error{CheckLegacyTxindex(*Assert(chainman.m_blockman.m_block_tree_db))}) {
1545
1459
  return InitError(*error);
1546
1460
  }
1547
1461
 
1548
- g_txindex = std::make_unique<TxIndex>(cache_sizes.tx_index, false, fReindex);
1549
- if (!g_txindex->Start(chainman.ActiveChainstate())) {
1550
- return false;
1551
- }
1462
+ g_txindex = std::make_unique<TxIndex>(cache_sizes.tx_index, false, fReindex);
1463
+ if (!g_txindex->Start(chainman.ActiveChainstate())) {
1464
+ return false;
1552
1465
  }
1553
1466
 
1554
1467
  for (const auto& filter_type : g_enabled_filter_types) {
@@ -1574,19 +1487,9 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1574
1487
 
1575
1488
  // ********************************************************* Step 10: data directory maintenance
1576
1489
 
1577
- // if pruning, unset the service bit and perform the initial blockstore prune
1578
- // after any wallet rescanning has taken place.
1579
- if (fPruneMode) {
1580
- LogPrintf("Unsetting NODE_NETWORK on prune mode\n");
1581
- nLocalServices = ServiceFlags(nLocalServices & ~NODE_NETWORK);
1582
- if (!fReindex) {
1583
- LOCK(cs_main);
1584
- for (CChainState* chainstate : chainman.GetAll()) {
1585
- uiInterface.InitMessage(_("Pruning blockstore…").translated);
1586
- chainstate->PruneAndFlush();
1587
- }
1588
- }
1589
- }
1490
+ // Note that setting NODE_WITNESS is never required: the only downside from not
1491
+ // doing so is that after activation, no upgraded nodes will fetch from you.
1492
+ nLocalServices = ServiceFlags(nLocalServices | NODE_WITNESS);
1590
1493
 
1591
1494
  // ********************************************************* Step 11: import blocks
1592
1495
 
@@ -1829,6 +1732,15 @@ bool AppInitMain(NodeContext& node, interfaces::BlockAndHeaderTipInfo* tip_info)
1829
1732
 
1830
1733
  #if HAVE_SYSTEM
1831
1734
  StartupNotify(args);
1735
+ #endif
1736
+ #ifdef ENABLE_WALLET
1737
+ {
1738
+ // ppctodo: deal with multiple wallets
1739
+ if (node.wallet_loader->getWallets().size() && gArgs.GetBoolArg("-stakegen", true)) {
1740
+ walletTmp = std::shared_ptr<CWallet>(node.wallet_loader->getWallets()[0]->wallet());
1741
+ MintStake(walletTmp, node);
1742
+ }
1743
+ }
1832
1744
  #endif
1833
1745
 
1834
1746
  return true;
src/int_utils.h ADDED
@@ -0,0 +1,290 @@
1
+ /**********************************************************************
2
+ * Copyright (c) 2018 Pieter Wuille, Greg Maxwell, Gleb Naumenko *
3
+ * Distributed under the MIT software license, see the accompanying *
4
+ * file LICENSE or http://www.opensource.org/licenses/mit-license.php.*
5
+ **********************************************************************/
6
+
7
+ #ifndef _MINISKETCH_INT_UTILS_H_
8
+ #define _MINISKETCH_INT_UTILS_H_
9
+
10
+ #include <stdlib.h>
11
+
12
+ #include <limits>
13
+ #include <algorithm>
14
+ #include <type_traits>
15
+
16
+ #ifdef _MSC_VER
17
+ # include <intrin.h>
18
+ #endif
19
+
20
+ template<int bits>
21
+ static constexpr inline uint64_t Rot(uint64_t x) { return (x << bits) | (x >> (64 - bits)); }
22
+
23
+ static inline void SipHashRound(uint64_t& v0, uint64_t& v1, uint64_t& v2, uint64_t& v3) {
24
+ v0 += v1; v1 = Rot<13>(v1); v1 ^= v0;
25
+ v0 = Rot<32>(v0);
26
+ v2 += v3; v3 = Rot<16>(v3); v3 ^= v2;
27
+ v0 += v3; v3 = Rot<21>(v3); v3 ^= v0;
28
+ v2 += v1; v1 = Rot<17>(v1); v1 ^= v2;
29
+ v2 = Rot<32>(v2);
30
+ }
31
+
32
+ inline uint64_t SipHash(uint64_t k0, uint64_t k1, uint64_t data) {
33
+ uint64_t v0 = 0x736f6d6570736575ULL ^ k0;
34
+ uint64_t v1 = 0x646f72616e646f6dULL ^ k1;
35
+ uint64_t v2 = 0x6c7967656e657261ULL ^ k0;
36
+ uint64_t v3 = 0x7465646279746573ULL ^ k1 ^ data;
37
+ SipHashRound(v0, v1, v2, v3);
38
+ SipHashRound(v0, v1, v2, v3);
39
+ v0 ^= data;
40
+ v3 ^= 0x800000000000000ULL;
41
+ SipHashRound(v0, v1, v2, v3);
42
+ SipHashRound(v0, v1, v2, v3);
43
+ v0 ^= 0x800000000000000ULL;
44
+ v2 ^= 0xFF;
45
+ SipHashRound(v0, v1, v2, v3);
46
+ SipHashRound(v0, v1, v2, v3);
47
+ SipHashRound(v0, v1, v2, v3);
48
+ SipHashRound(v0, v1, v2, v3);
49
+ return v0 ^ v1 ^ v2 ^ v3;
50
+ }
51
+
52
+ class BitWriter {
53
+ unsigned char state = 0;
54
+ int offset = 0;
55
+ unsigned char* out;
56
+
57
+ public:
58
+ BitWriter(unsigned char* output) : out(output) {}
59
+
60
+ template<int BITS, typename I>
61
+ inline void Write(I val) {
62
+ int bits = BITS;
63
+ if (bits + offset >= 8) {
64
+ state |= ((val & ((I(1) << (8 - offset)) - 1)) << offset);
65
+ *(out++) = state;
66
+ val >>= (8 - offset);
67
+ bits -= 8 - offset;
68
+ offset = 0;
69
+ state = 0;
70
+ }
71
+ while (bits >= 8) {
72
+ *(out++) = val & 255;
73
+ val >>= 8;
74
+ bits -= 8;
75
+ }
76
+ state |= ((val & ((I(1) << bits) - 1)) << offset);
77
+ offset += bits;
78
+ }
79
+
80
+ inline void Flush() {
81
+ if (offset) {
82
+ *(out++) = state;
83
+ state = 0;
84
+ offset = 0;
85
+ }
86
+ }
87
+ };
88
+
89
+ class BitReader {
90
+ unsigned char state = 0;
91
+ int offset = 0;
92
+ const unsigned char* in;
93
+
94
+ public:
95
+ BitReader(const unsigned char* input) : in(input) {}
96
+
97
+ template<int BITS, typename I>
98
+ inline I Read() {
99
+ int bits = BITS;
100
+ if (offset >= bits) {
101
+ I ret = state & ((1 << bits) - 1);
102
+ state >>= bits;
103
+ offset -= bits;
104
+ return ret;
105
+ }
106
+ I val = state;
107
+ int out = offset;
108
+ while (out + 8 <= bits) {
109
+ val |= ((I(*(in++))) << out);
110
+ out += 8;
111
+ }
112
+ if (out < bits) {
113
+ unsigned char c = *(in++);
114
+ val |= (c & ((I(1) << (bits - out)) - 1)) << out;
115
+ state = c >> (bits - out);
116
+ offset = 8 - (bits - out);
117
+ } else {
118
+ state = 0;
119
+ offset = 0;
120
+ }
121
+ return val;
122
+ }
123
+ };
124
+
125
+ /** Return a value of type I with its `bits` lowest bits set (bits must be > 0). */
126
+ template<int BITS, typename I>
127
+ constexpr inline I Mask() { return ((I((I(-1)) << (std::numeric_limits<I>::digits - BITS))) >> (std::numeric_limits<I>::digits - BITS)); }
128
+
129
+ /** Compute the smallest power of two that is larger than val. */
130
+ template<typename I>
131
+ static inline int CountBits(I val, int max) {
132
+ #ifdef HAVE_CLZ
133
+ (void)max;
134
+ if (val == 0) return 0;
135
+ if (std::numeric_limits<unsigned>::digits >= std::numeric_limits<I>::digits) {
136
+ return std::numeric_limits<unsigned>::digits - __builtin_clz(val);
137
+ } else if (std::numeric_limits<unsigned long>::digits >= std::numeric_limits<I>::digits) {
138
+ return std::numeric_limits<unsigned long>::digits - __builtin_clzl(val);
139
+ } else {
140
+ return std::numeric_limits<unsigned long long>::digits - __builtin_clzll(val);
141
+ }
142
+ #elif _MSC_VER
143
+ (void)max;
144
+ unsigned long index;
145
+ unsigned char ret;
146
+ if (std::numeric_limits<I>::digits <= 32) {
147
+ ret = _BitScanReverse(&index, val);
148
+ } else {
149
+ ret = _BitScanReverse64(&index, val);
150
+ }
151
+ if (!ret) return 0;
152
+ return index;
153
+ #else
154
+ while (max && (val >> (max - 1) == 0)) --max;
155
+ return max;
156
+ #endif
157
+ }
158
+
159
+ template<typename I, int BITS>
160
+ class BitsInt {
161
+ private:
162
+ static_assert(std::is_integral<I>::value && std::is_unsigned<I>::value, "BitsInt requires an unsigned integer type");
163
+ static_assert(BITS > 0 && BITS <= std::numeric_limits<I>::digits, "BitsInt requires 1 <= Bits <= representation type size");
164
+
165
+ static constexpr I MASK = Mask<BITS, I>();
166
+
167
+ public:
168
+
169
+ typedef I Repr;
170
+
171
+ static constexpr int SIZE = BITS;
172
+
173
+ static void inline Swap(I& a, I& b) {
174
+ std::swap(a, b);
175
+ }
176
+
177
+ static constexpr inline bool IsZero(I a) { return a == 0; }
178
+ static constexpr inline I Mask(I val) { return val & MASK; }
179
+ static constexpr inline I Shift(I val, int bits) { return ((val << bits) & MASK); }
180
+ static constexpr inline I UnsafeShift(I val, int bits) { return (val << bits); }
181
+
182
+ template<int Offset, int Count>
183
+ static constexpr inline int MidBits(I val) {
184
+ static_assert(Count > 0, "BITSInt::MidBits needs Count > 0");
185
+ static_assert(Count + Offset <= BITS, "BitsInt::MidBits overflow of Count+Offset");
186
+ return (val >> Offset) & ((I(1) << Count) - 1);
187
+ }
188
+
189
+ template<int Count>
190
+ static constexpr inline int TopBits(I val) {
191
+ static_assert(Count > 0, "BitsInt::TopBits needs Count > 0");
192
+ static_assert(Count <= BITS, "BitsInt::TopBits needs Offset <= BITS");
193
+ return val >> (BITS - Count);
194
+ }
195
+
196
+ static inline constexpr I CondXorWith(I val, bool cond, I v) {
197
+ return val ^ (-I(cond) & v);
198
+ }
199
+
200
+ template<I MOD>
201
+ static inline constexpr I CondXorWith(I val, bool cond) {
202
+ return val ^ (-I(cond) & MOD);
203
+ }
204
+
205
+ static inline int Bits(I val, int max) { return CountBits<I>(val, max); }
206
+ };
207
+
208
+ /** Class which implements a stateless LFSR for generic moduli. */
209
+ template<typename F, uint32_t MOD>
210
+ struct LFSR {
211
+ typedef typename F::Repr I;
212
+ /** Shift a value `a` up once, treating it as an `N`-bit LFSR, with pattern `MOD`. */
213
+ static inline constexpr I Call(const I& a) {
214
+ return F::template CondXorWith<MOD>(F::Shift(a, 1), F::template TopBits<1>(a));
215
+ }
216
+ };
217
+
218
+ /** Helper class for carryless multiplications. */
219
+ template<typename I, int N, typename L, typename F, int K> struct GFMulHelper;
220
+ template<typename I, int N, typename L, typename F> struct GFMulHelper<I, N, L, F, 0>
221
+ {
222
+ static inline constexpr I Run(const I& a, const I& b) { return I(0); }
223
+ };
224
+ template<typename I, int N, typename L, typename F, int K> struct GFMulHelper
225
+ {
226
+ static inline constexpr I Run(const I& a, const I& b) { return F::CondXorWith(GFMulHelper<I, N, L, F, K - 1>::Run(L::Call(a), b), F::template MidBits<N - K, 1>(b), a); }
227
+ };
228
+
229
+ /** Compute the carry-less multiplication of a and b, with N bits, using L as LFSR type. */
230
+ template<typename I, int N, typename L, typename F> inline constexpr I GFMul(const I& a, const I& b) { return GFMulHelper<I, N, L, F, N>::Run(a, b); }
231
+
232
+ /** Compute the inverse of x using an extgcd algorithm. */
233
+ template<typename I, typename F, int BITS, uint32_t MOD>
234
+ inline I InvExtGCD(I x)
235
+ {
236
+ if (F::IsZero(x)) return x;
237
+ I t(0), newt(1);
238
+ I r(MOD), newr = x;
239
+ int rlen = BITS + 1, newrlen = F::Bits(newr, BITS);
240
+ while (newr) {
241
+ int q = rlen - newrlen;
242
+ r ^= F::Shift(newr, q);
243
+ t ^= F::UnsafeShift(newt, q);
244
+ rlen = F::Bits(r, rlen - 1);
245
+ if (r < newr) {
246
+ F::Swap(t, newt);
247
+ F::Swap(r, newr);
248
+ std::swap(rlen, newrlen);
249
+ }
250
+ }
251
+ return t;
252
+ }
253
+
254
+ /** Compute the inverse of x1 using an exponentiation ladder.
255
+ *
256
+ * The `MUL` argument is a multiplication function, `SQR` is a squaring function, and the `SQRi` arguments
257
+ * compute x**(2**i).
258
+ */
259
+ template<typename I, typename F, int BITS, I (*MUL)(I, I), I (*SQR)(I), I (*SQR2)(I), I(*SQR4)(I), I(*SQR8)(I), I(*SQR16)(I)>
260
+ inline I InvLadder(I x1)
261
+ {
262
+ static constexpr int INV_EXP = BITS - 1;
263
+ I x2 = (INV_EXP >= 2) ? MUL(SQR(x1), x1) : I();
264
+ I x4 = (INV_EXP >= 4) ? MUL(SQR2(x2), x2) : I();
265
+ I x8 = (INV_EXP >= 8) ? MUL(SQR4(x4), x4) : I();
266
+ I x16 = (INV_EXP >= 16) ? MUL(SQR8(x8), x8) : I();
267
+ I x32 = (INV_EXP >= 32) ? MUL(SQR16(x16), x16) : I();
268
+ I r;
269
+ if (INV_EXP >= 32) {
270
+ r = x32;
271
+ } else if (INV_EXP >= 16) {
272
+ r = x16;
273
+ } else if (INV_EXP >= 8) {
274
+ r = x8;
275
+ } else if (INV_EXP >= 4) {
276
+ r = x4;
277
+ } else if (INV_EXP >= 2) {
278
+ r = x2;
279
+ } else {
280
+ r = x1;
281
+ }
282
+ if (INV_EXP >= 32 && (INV_EXP & 16)) r = MUL(SQR16(r), x16);
283
+ if (INV_EXP >= 16 && (INV_EXP & 8)) r = MUL(SQR8(r), x8);
284
+ if (INV_EXP >= 8 && (INV_EXP & 4)) r = MUL(SQR4(r), x4);
285
+ if (INV_EXP >= 4 && (INV_EXP & 2)) r = MUL(SQR2(r), x2);
286
+ if (INV_EXP >= 2 && (INV_EXP & 1)) r = MUL(SQR(r), x1);
287
+ return SQR(r);
288
+ }
289
+
290
+ #endif
src/interfaces/chain.h CHANGED
@@ -5,6 +5,7 @@
5
5
  #ifndef BITCOIN_INTERFACES_CHAIN_H
6
6
  #define BITCOIN_INTERFACES_CHAIN_H
7
7
 
8
+ #include <node/chainstate.h>
8
9
  #include <primitives/transaction.h> // For CTransactionRef
9
10
  #include <util/settings.h> // For util::SettingsValue
10
11
 
@@ -18,16 +19,13 @@
18
19
 
19
20
  class ArgsManager;
20
21
  class CBlock;
21
- class CFeeRate;
22
22
  class CRPCCommand;
23
23
  class CScheduler;
24
24
  class Coin;
25
25
  class uint256;
26
26
  enum class MemPoolRemovalReason;
27
- enum class RBFTransactionState;
28
27
  struct bilingual_str;
29
28
  struct CBlockLocator;
30
- struct FeeCalculation;
31
29
  namespace node {
32
30
  struct NodeContext;
33
31
  } // namespace node
@@ -96,6 +94,8 @@ class Chain
96
94
  public:
97
95
  virtual ~Chain() {}
98
96
 
97
+ virtual ChainstateManager& chainman() = 0;
98
+
99
99
  //! Get current chain height, not including genesis block (returns 0 if
100
100
  //! chain only contains genesis block, nullopt if chain does not contain
101
101
  //! any blocks)
@@ -104,8 +104,7 @@ public:
104
104
  //! Get block hash. Height must be valid or this function will abort.
105
105
  virtual uint256 getBlockHash(int height) = 0;
106
106
 
107
- //! Check that the block is available on disk (i.e. has not been
108
- //! pruned), and contains transactions.
107
+ //! Check that the block is available on disk, and contains transactions.
109
108
  virtual bool haveBlockOnDisk(int height) = 0;
110
109
 
111
110
  //! Get locator for the current chain tip.
@@ -158,9 +157,6 @@ public:
158
157
  //! the height range from min_height to max_height, inclusive.
159
158
  virtual bool hasBlocks(const uint256& block_hash, int min_height = 0, std::optional<int> max_height = {}) = 0;
160
159
 
161
- //! Check if transaction is RBF opt in.
162
- virtual RBFTransactionState isRBFOptIn(const CTransaction& tx) = 0;
163
-
164
160
  //! Check if transaction is in mempool.
165
161
  virtual bool isInMempool(const uint256& txid) = 0;
166
162
 
@@ -171,7 +167,6 @@ public:
171
167
  //! amount specified by max_tx_fee, and broadcast to all peers if relay is set to true.
172
168
  //! Return false if the transaction could not be added due to the fee or for another reason.
173
169
  virtual bool broadcastTransaction(const CTransactionRef& tx,
174
- const CAmount& max_tx_fee,
175
170
  bool relay,
176
171
  std::string& err_string) = 0;
177
172
 
@@ -186,27 +181,6 @@ public:
186
181
  //! Check if transaction will pass the mempool's chain limits.
187
182
  virtual bool checkChainLimits(const CTransactionRef& tx) = 0;
188
183
 
189
- //! Estimate smart fee.
190
- virtual CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc = nullptr) = 0;
191
-
192
- //! Fee estimator max target.
193
- virtual unsigned int estimateMaxBlocks() = 0;
194
-
195
- //! Mempool minimum fee.
196
- virtual CFeeRate mempoolMinFee() = 0;
197
-
198
- //! Relay current minimum fee (from -minrelaytxfee and -incrementalrelayfee settings).
199
- virtual CFeeRate relayMinFee() = 0;
200
-
201
- //! Relay incremental fee setting (-incrementalrelayfee), reflecting cost of relay.
202
- virtual CFeeRate relayIncrementalFee() = 0;
203
-
204
- //! Relay dust fee setting (-dustrelayfee), reflecting lowest rate it's economical to spend.
205
- virtual CFeeRate relayDustFee() = 0;
206
-
207
- //! Check if any block has been pruned.
208
- virtual bool havePruned() = 0;
209
-
210
184
  //! Check if the node is ready to broadcast transactions.
211
185
  virtual bool isReadyToBroadcast() = 0;
212
186
 
src/interfaces/init.h CHANGED
@@ -6,6 +6,9 @@
6
6
  #define BITCOIN_INTERFACES_INIT_H
7
7
 
8
8
  #include <memory>
9
+ #include <interfaces/wallet.h>
10
+
11
+ using interfaces::WalletLoader;
9
12
 
10
13
  namespace node {
11
14
  struct NodeContext;
@@ -16,7 +19,7 @@ class Chain;
16
19
  class Echo;
17
20
  class Ipc;
18
21
  class Node;
19
- class WalletLoader;
22
+ //class WalletLoader;
20
23
 
21
24
  //! Initial interface created when a process is first started, and used to give
22
25
  //! and get access to other interfaces (Node, Chain, Wallet, etc).
src/interfaces/node.h CHANGED
@@ -6,11 +6,13 @@
6
6
  #define BITCOIN_INTERFACES_NODE_H
7
7
 
8
8
  #include <consensus/amount.h>
9
+ #include <node/chainstate.h>
9
10
  #include <net.h> // For NodeId
10
11
  #include <net_types.h> // For banmap_t
11
12
  #include <netaddress.h> // For Network
12
13
  #include <netbase.h> // For ConnectionDirection
13
14
  #include <support/allocators/secure.h> // For SecureString
15
+ #include <util/ui_change_type.h>
14
16
  #include <util/translation.h>
15
17
 
16
18
  #include <functional>
@@ -22,7 +24,6 @@
22
24
  #include <vector>
23
25
 
24
26
  class BanMan;
25
- class CFeeRate;
26
27
  class CNodeStats;
27
28
  class Coin;
28
29
  class RPCTimerInterface;
@@ -70,6 +71,8 @@ class Node
70
71
  public:
71
72
  virtual ~Node() {}
72
73
 
74
+ virtual ChainstateManager& chainman() = 0;
75
+
73
76
  //! Init logging.
74
77
  virtual void initLogging() = 0;
75
78
 
@@ -170,9 +173,6 @@ public:
170
173
  //! Get network active.
171
174
  virtual bool getNetworkActive() = 0;
172
175
 
173
- //! Get dust relay fee.
174
- virtual CFeeRate getDustRelayFee() = 0;
175
-
176
176
  //! Execute rpc command.
177
177
  virtual UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) = 0;
178
178
 
@@ -189,7 +189,7 @@ public:
189
189
  virtual bool getUnspentOutput(const COutPoint& output, Coin& coin) = 0;
190
190
 
191
191
  //! Broadcast transaction.
192
- virtual TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, std::string& err_string) = 0;
192
+ virtual TransactionError broadcastTransaction(CTransactionRef tx, std::string& err_string) = 0;
193
193
 
194
194
  //! Get wallet loader.
195
195
  virtual WalletLoader& walletLoader() = 0;
@@ -227,7 +227,7 @@ public:
227
227
  virtual std::unique_ptr<Handler> handleNotifyNetworkActiveChanged(NotifyNetworkActiveChangedFn fn) = 0;
228
228
 
229
229
  //! Register handler for notify alert messages.
230
- using NotifyAlertChangedFn = std::function<void()>;
230
+ using NotifyAlertChangedFn = std::function<void(const uint256 &hash, ChangeType status)>;
231
231
  virtual std::unique_ptr<Handler> handleNotifyAlertChanged(NotifyAlertChangedFn fn) = 0;
232
232
 
233
233
  //! Register handler for ban list messages.
src/interfaces/wallet.h CHANGED
@@ -24,7 +24,6 @@
24
24
  #include <utility>
25
25
  #include <vector>
26
26
 
27
- class CFeeRate;
28
27
  class CKey;
29
28
  enum class FeeReason;
30
29
  enum class OutputType;
@@ -156,26 +155,6 @@ public:
156
155
  //! Abandon transaction.
157
156
  virtual bool abandonTransaction(const uint256& txid) = 0;
158
157
 
159
- //! Return whether transaction can be bumped.
160
- virtual bool transactionCanBeBumped(const uint256& txid) = 0;
161
-
162
- //! Create bump transaction.
163
- virtual bool createBumpTransaction(const uint256& txid,
164
- const wallet::CCoinControl& coin_control,
165
- std::vector<bilingual_str>& errors,
166
- CAmount& old_fee,
167
- CAmount& new_fee,
168
- CMutableTransaction& mtx) = 0;
169
-
170
- //! Sign bump transaction.
171
- virtual bool signBumpTransaction(CMutableTransaction& mtx) = 0;
172
-
173
- //! Commit bump transaction.
174
- virtual bool commitBumpTransaction(const uint256& txid,
175
- CMutableTransaction&& mtx,
176
- std::vector<bilingual_str>& errors,
177
- uint256& bumped_txid) = 0;
178
-
179
158
  //! Get a transaction.
180
159
  virtual CTransactionRef getTx(const uint256& txid) = 0;
181
160
 
@@ -237,7 +216,7 @@ public:
237
216
 
238
217
  //! Return wallet transaction output information.
239
218
  virtual std::vector<WalletTxOut> getCoins(const std::vector<COutPoint>& outputs) = 0;
240
-
219
+ /*
241
220
  //! Get required fee.
242
221
  virtual CAmount getRequiredFee(unsigned int tx_bytes) = 0;
243
222
 
@@ -249,7 +228,7 @@ public:
249
228
 
250
229
  //! Get tx confirm target.
251
230
  virtual unsigned int getConfirmTarget() = 0;
252
-
231
+ */
253
232
  // Return whether HD enabled.
254
233
  virtual bool hdEnabled() = 0;
255
234
 
@@ -268,9 +247,6 @@ public:
268
247
  // Get default address type.
269
248
  virtual OutputType getDefaultAddressType() = 0;
270
249
 
271
- //! Get max tx fee.
272
- virtual CAmount getDefaultMaxTxFee() = 0;
273
-
274
250
  // Remove wallet.
275
251
  virtual void remove() = 0;
276
252
 
@@ -311,6 +287,9 @@ public:
311
287
 
312
288
  //! Return pointer to internal wallet class, useful for testing.
313
289
  virtual wallet::CWallet* wallet() { return nullptr; }
290
+ // peercoin
291
+ virtual void relockWalletAfterDuration(int nDuration) = 0;
292
+ virtual std::shared_ptr<wallet::CWallet> getWallet() = 0;
314
293
  };
315
294
 
316
295
  //! Wallet chain client that in addition to having chain client methods for
@@ -365,6 +344,7 @@ struct WalletAddress
365
344
  struct WalletBalances
366
345
  {
367
346
  CAmount balance = 0;
347
+ CAmount stake = 0;
368
348
  CAmount unconfirmed_balance = 0;
369
349
  CAmount immature_balance = 0;
370
350
  bool have_watch_only = false;
@@ -374,7 +354,7 @@ struct WalletBalances
374
354
 
375
355
  bool balanceChanged(const WalletBalances& prev) const
376
356
  {
377
- return balance != prev.balance || unconfirmed_balance != prev.unconfirmed_balance ||
357
+ return balance != prev.balance || stake != prev.stake || unconfirmed_balance != prev.unconfirmed_balance ||
378
358
  immature_balance != prev.immature_balance || watch_only_balance != prev.watch_only_balance ||
379
359
  unconfirmed_watch_only_balance != prev.unconfirmed_watch_only_balance ||
380
360
  immature_watch_only_balance != prev.immature_watch_only_balance;
@@ -395,6 +375,7 @@ struct WalletTx
395
375
  int64_t time;
396
376
  std::map<std::string, std::string> value_map;
397
377
  bool is_coinbase;
378
+ bool is_coinstake;
398
379
  };
399
380
 
400
381
  //! Updated transaction status.
@@ -408,6 +389,7 @@ struct WalletTxStatus
408
389
  bool is_trusted;
409
390
  bool is_abandoned;
410
391
  bool is_coinbase;
392
+ bool is_coinstake;
411
393
  bool is_in_main_chain;
412
394
  };
413
395
 
src/kernel.cpp ADDED
@@ -0,0 +1,725 @@
1
+ // Copyright (c) 2012-2023 The Peercoin developers
2
+ // Distributed under the MIT software license, see the accompanying
3
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
+
5
+ #include <kernel.h>
6
+ #include <chainparams.h>
7
+ #include <validation.h>
8
+ #include <streams.h>
9
+ #include <timedata.h>
10
+ #include <bignum.h>
11
+ #include <txdb.h>
12
+ #include <consensus/validation.h>
13
+ #include <validation.h>
14
+ #include <random.h>
15
+ #include <script/interpreter.h>
16
+
17
+ #include <index/txindex.h>
18
+
19
+ #include <boost/assign/list_of.hpp>
20
+
21
+ using namespace std;
22
+
23
+ // Protocol switch time of v0.3 kernel protocol
24
+ unsigned int nProtocolV03SwitchTime = 1363800000;
25
+ unsigned int nProtocolV03TestSwitchTime = 1359781000;
26
+ // Protocol switch time of v0.4 kernel protocol
27
+ unsigned int nProtocolV04SwitchTime = 1399300000;
28
+ unsigned int nProtocolV04TestSwitchTime = 1395700000;
29
+ // Protocol switch time of v0.5 kernel protocol
30
+ unsigned int nProtocolV05SwitchTime = 1461700000;
31
+ unsigned int nProtocolV05TestSwitchTime = 1447700000;
32
+ // Protocol switch time of v0.6 kernel protocol
33
+ // supermajority hardfork: actual fork will happen later than switch time
34
+ const unsigned int nProtocolV06SwitchTime = 1513050000; // Tue 12 Dec 03:40:00 UTC 2017
35
+ const unsigned int nProtocolV06TestSwitchTime = 1508198400; // Tue 17 Oct 00:00:00 UTC 2017
36
+ // Protocol switch time for 0.7 kernel protocol
37
+ const unsigned int nProtocolV07SwitchTime = 1552392000; // Tue 12 Mar 12:00:00 UTC 2019
38
+ const unsigned int nProtocolV07TestSwitchTime = 1541505600; // Tue 06 Nov 12:00:00 UTC 2018
39
+ // Switch time for new BIPs from bitcoin 0.16.x
40
+ const uint32_t nBTC16BIPsSwitchTime = 1569931200; // Tue 01 Oct 12:00:00 UTC 2019
41
+ const uint32_t nBTC16BIPsTestSwitchTime = 1554811200; // Tue 09 Apr 12:00:00 UTC 2019
42
+ // Protocol switch time for v0.9 kernel protocol
43
+ const unsigned int nProtocolV09SwitchTime = 1591617600; // Mon 8 Jun 12:00:00 UTC 2020
44
+ const unsigned int nProtocolV09TestSwitchTime = 1581940800; // Mon 17 Feb 12:00:00 UTC 2020
45
+ // Protocol switch time for v10 kernel protocol
46
+ const unsigned int nProtocolV10SwitchTime = 1635768000; // Mon 1 Nov 12:00:00 UTC 2021
47
+ const unsigned int nProtocolV10TestSwitchTime = 1625140800; // Thu 1 Jul 12:00:00 UTC 2021
48
+ // Protocol switch time for v12 kernel protocol
49
+ const unsigned int nProtocolV12SwitchTime = 1681732800; // Mon 17 Apr 12:00:00 UTC 2023
50
+ const unsigned int nProtocolV12TestSwitchTime = 1669636800; // Mon 28 Nov 12:00:00 UTC 2022
51
+
52
+ // Hard checkpoints of stake modifiers to ensure they are deterministic
53
+ static std::map<int, unsigned int> mapStakeModifierCheckpoints =
54
+ boost::assign::map_list_of
55
+ ( 0, 0x0e00670bu )
56
+ ( 19080, 0xad4e4d29u )
57
+ ( 30583, 0xdc7bf136u )
58
+ ( 99999, 0xf555cfd2u )
59
+ (219999, 0x91b7444du )
60
+ (336000, 0x6c3c8048u )
61
+ (371850, 0x9b850bdfu )
62
+ (407813, 0x46fe50b5u )
63
+ (443561, 0x114a6e38u )
64
+ (455470, 0x9b7af181u )
65
+ (479189, 0xe04fb8e0u )
66
+ (504051, 0x459f5a16u )
67
+ (589659, 0xbd02492au )
68
+ ;
69
+
70
+ static std::map<int, unsigned int> mapStakeModifierTestnetCheckpoints =
71
+ boost::assign::map_list_of
72
+ ( 0, 0x0e00670bu )
73
+ ( 19080, 0x3711dc3au )
74
+ ( 30583, 0xb480fadeu )
75
+ ( 99999, 0x9a62eaecu )
76
+ (219999, 0xeafe96c3u )
77
+ (336000, 0x8330dc09u )
78
+ (372751, 0xafb94e2fu )
79
+ (382019, 0x7f5cf5ebu )
80
+ (408500, 0x68cadee2u )
81
+ (412691, 0x93138e67u )
82
+ (441299, 0x03e195cbu )
83
+ (442735, 0xe42d94feu )
84
+ ;
85
+
86
+ // Whether the given coinstake is subject to new v0.3 protocol
87
+ bool IsProtocolV03(unsigned int nTimeCoinStake)
88
+ {
89
+ return (nTimeCoinStake >= (Params().NetworkIDString() != CBaseChainParams::MAIN ? nProtocolV03TestSwitchTime : nProtocolV03SwitchTime));
90
+ }
91
+
92
+ // Whether the given block is subject to new v0.4 protocol
93
+ bool IsProtocolV04(unsigned int nTimeBlock)
94
+ {
95
+ return (nTimeBlock >= (Params().NetworkIDString() != CBaseChainParams::MAIN ? nProtocolV04TestSwitchTime : nProtocolV04SwitchTime));
96
+ }
97
+
98
+ // Whether the given transaction is subject to new v0.5 protocol
99
+ bool IsProtocolV05(unsigned int nTimeTx)
100
+ {
101
+ return (nTimeTx >= (Params().NetworkIDString() != CBaseChainParams::MAIN ? nProtocolV05TestSwitchTime : nProtocolV05SwitchTime));
102
+ }
103
+
104
+ // Whether a given block is subject to new v0.6 protocol
105
+ // Test against previous block index! (always available)
106
+ bool IsProtocolV06(const CBlockIndex* pindexPrev)
107
+ {
108
+ if (pindexPrev->nTime < (Params().NetworkIDString() != CBaseChainParams::MAIN ? nProtocolV06TestSwitchTime : nProtocolV06SwitchTime))
109
+ return false;
110
+
111
+ // if 900 of the last 1,000 blocks are version 2 or greater (90/100 if testnet):
112
+ // Soft-forking PoS can be dangerous if the super majority is too low
113
+ // The stake majority will decrease after the fork
114
+ // since only coindays of updated nodes will get destroyed.
115
+ if ((Params().NetworkIDString() == CBaseChainParams::MAIN && IsSuperMajority(2, pindexPrev, 900, 1000)) ||
116
+ (Params().NetworkIDString() != CBaseChainParams::MAIN && IsSuperMajority(2, pindexPrev, 90, 100)))
117
+ return true;
118
+
119
+ return false;
120
+ }
121
+
122
+ // Whether a given transaction is subject to new v0.7 protocol
123
+ bool IsProtocolV07(unsigned int nTimeTx)
124
+ {
125
+ bool fTestNet = Params().NetworkIDString() != CBaseChainParams::MAIN;
126
+ return (nTimeTx >= (fTestNet? nProtocolV07TestSwitchTime : nProtocolV07SwitchTime));
127
+ }
128
+
129
+ bool IsBTC16BIPsEnabled(uint32_t nTimeTx)
130
+ {
131
+ bool fTestNet = Params().NetworkIDString() != CBaseChainParams::MAIN;
132
+ return (nTimeTx >= (fTestNet? nBTC16BIPsTestSwitchTime : nBTC16BIPsSwitchTime));
133
+ }
134
+
135
+ // Whether a given timestamp is subject to new v0.9 protocol
136
+ bool IsProtocolV09(unsigned int nTime)
137
+ {
138
+ return (nTime >= (Params().NetworkIDString() != CBaseChainParams::MAIN ? nProtocolV09TestSwitchTime : nProtocolV09SwitchTime));
139
+ }
140
+
141
+ // Whether a given timestamp is subject to new v10 protocol
142
+ bool IsProtocolV10(unsigned int nTime)
143
+ {
144
+ return (nTime >= (Params().NetworkIDString() != CBaseChainParams::MAIN ? nProtocolV10TestSwitchTime : nProtocolV10SwitchTime));
145
+ }
146
+
147
+ // Whether a given timestamp is subject to new v10 protocol
148
+ bool IsProtocolV12(const CBlockIndex* pindexPrev)
149
+ {
150
+ if (pindexPrev->nTime < (Params().NetworkIDString() != CBaseChainParams::MAIN ? nProtocolV12TestSwitchTime : nProtocolV12SwitchTime))
151
+ return false;
152
+
153
+ if ((Params().NetworkIDString() == CBaseChainParams::MAIN && IsSuperMajority(4, pindexPrev, 900, 1000)) ||
154
+ (Params().NetworkIDString() != CBaseChainParams::MAIN && IsSuperMajority(4, pindexPrev, 90, 100)))
155
+ return true;
156
+
157
+ return false;
158
+ }
159
+
160
+ // Get the last stake modifier and its generation time from a given block
161
+ static bool GetLastStakeModifier(const CBlockIndex* pindex, uint64_t& nStakeModifier, int64_t& nModifierTime)
162
+ {
163
+ if (!pindex)
164
+ return error("GetLastStakeModifier: null pindex");
165
+ while (pindex && pindex->pprev && !pindex->GeneratedStakeModifier())
166
+ pindex = pindex->pprev;
167
+ if (!pindex->GeneratedStakeModifier())
168
+ return error("GetLastStakeModifier: no generation at genesis block");
169
+ nStakeModifier = pindex->nStakeModifier;
170
+ nModifierTime = pindex->GetBlockTime();
171
+ return true;
172
+ }
173
+
174
+ // Get selection interval section (in seconds)
175
+ static int64_t GetStakeModifierSelectionIntervalSection(int nSection)
176
+ {
177
+ assert (nSection >= 0 && nSection < 64);
178
+ return (Params().GetConsensus().nModifierInterval * 63 / (63 + ((63 - nSection) * (MODIFIER_INTERVAL_RATIO - 1))));
179
+ }
180
+
181
+ // Get stake modifier selection interval (in seconds)
182
+ static int64_t GetStakeModifierSelectionInterval()
183
+ {
184
+ int64_t nSelectionInterval = 0;
185
+ for (int nSection=0; nSection<64; nSection++)
186
+ nSelectionInterval += GetStakeModifierSelectionIntervalSection(nSection);
187
+ return nSelectionInterval;
188
+ }
189
+
190
+ // select a block from the candidate blocks in vSortedByTimestamp, excluding
191
+ // already selected blocks in vSelectedBlocks, and with timestamp up to
192
+ // nSelectionIntervalStop.
193
+ static bool SelectBlockFromCandidates(
194
+ vector<pair<int64_t, uint256> >& vSortedByTimestamp,
195
+ map<uint256, const CBlockIndex*>& mapSelectedBlocks,
196
+ int64_t nSelectionIntervalStop, uint64_t nStakeModifierPrev,
197
+ const CBlockIndex** pindexSelected,
198
+ CChainState& chainstate)
199
+ {
200
+ bool fSelected = false;
201
+ arith_uint256 hashBest = 0;
202
+ *pindexSelected = (const CBlockIndex*) 0;
203
+ for (const auto& item : vSortedByTimestamp)
204
+ {
205
+ /*
206
+ if (!chainstate.BlockIndex().count(item.second))
207
+ return error("SelectBlockFromCandidates: failed to find block index for candidate block %s", item.second.ToString());
208
+ const CBlockIndex* pindex = pindexSelected.BlockIndex()[item.second];
209
+ */
210
+ const CBlockIndex* pindex = chainstate.m_blockman.LookupBlockIndex(item.second);
211
+ if (!pindex)
212
+ return error("SelectBlockFromCandidates: failed to find block index for candidate block %s", item.second.ToString());
213
+
214
+ if (fSelected && pindex->GetBlockTime() > nSelectionIntervalStop)
215
+ break;
216
+ if (mapSelectedBlocks.count(pindex->GetBlockHash()) > 0)
217
+ continue;
218
+ // compute the selection hash by hashing its proof-hash and the
219
+ // previous proof-of-stake modifier
220
+ uint256 hashProof = pindex->IsProofOfStake()? pindex->hashProofOfStake : pindex->GetBlockHash();
221
+ CDataStream ss(SER_GETHASH, 0);
222
+ ss << hashProof << nStakeModifierPrev;
223
+ arith_uint256 hashSelection = UintToArith256(Hash(ss));
224
+ // the selection hash is divided by 2**32 so that proof-of-stake block
225
+ // is always favored over proof-of-work block. this is to preserve
226
+ // the energy efficiency property
227
+ if (pindex->IsProofOfStake())
228
+ hashSelection >>= 32;
229
+ if (fSelected && hashSelection < hashBest)
230
+ {
231
+ hashBest = hashSelection;
232
+ *pindexSelected = (const CBlockIndex*) pindex;
233
+ }
234
+ else if (!fSelected)
235
+ {
236
+ fSelected = true;
237
+ hashBest = hashSelection;
238
+ *pindexSelected = (const CBlockIndex*) pindex;
239
+ }
240
+ }
241
+ if (gArgs.GetBoolArg("-debug", false) && gArgs.GetBoolArg("-printstakemodifier", false))
242
+ LogPrintf("SelectBlockFromCandidates: selection hash=%s\n", hashBest.ToString());
243
+ return fSelected;
244
+ }
245
+
246
+ // Stake Modifier (hash modifier of proof-of-stake):
247
+ // The purpose of stake modifier is to prevent a txout (coin) owner from
248
+ // computing future proof-of-stake generated by this txout at the time
249
+ // of transaction confirmation. To meet kernel protocol, the txout
250
+ // must hash with a future stake modifier to generate the proof.
251
+ // Stake modifier consists of bits each of which is contributed from a
252
+ // selected block of a given block group in the past.
253
+ // The selection of a block is based on a hash of the block's proof-hash and
254
+ // the previous stake modifier.
255
+ // Stake modifier is recomputed at a fixed time interval instead of every
256
+ // block. This is to make it difficult for an attacker to gain control of
257
+ // additional bits in the stake modifier, even after generating a chain of
258
+ // blocks.
259
+ bool ComputeNextStakeModifier(const CBlockIndex* pindexCurrent, uint64_t &nStakeModifier, bool& fGeneratedStakeModifier, CChainState& chainstate)
260
+ {
261
+ const Consensus::Params& params = Params().GetConsensus();
262
+ const CBlockIndex* pindexPrev = pindexCurrent->pprev;
263
+ nStakeModifier = 0;
264
+ fGeneratedStakeModifier = false;
265
+ if (!pindexPrev)
266
+ {
267
+ fGeneratedStakeModifier = true;
268
+ return true; // genesis block's modifier is 0
269
+ }
270
+ // First find current stake modifier and its generation block time
271
+ // if it's not old enough, return the same stake modifier
272
+ int64_t nModifierTime = 0;
273
+ if (!GetLastStakeModifier(pindexPrev, nStakeModifier, nModifierTime))
274
+ return error("ComputeNextStakeModifier: unable to get last modifier");
275
+ if (gArgs.GetBoolArg("-debug", false))
276
+ LogPrintf("ComputeNextStakeModifier: prev modifier=0x%016x time=%s epoch=%u\n", nStakeModifier, FormatISO8601DateTime(nModifierTime), (unsigned int)nModifierTime);
277
+ if (nModifierTime / params.nModifierInterval >= pindexPrev->GetBlockTime() / params.nModifierInterval)
278
+ {
279
+ if (gArgs.GetBoolArg("-debug", false))
280
+ LogPrintf("ComputeNextStakeModifier: no new interval keep current modifier: pindexPrev nHeight=%d nTime=%u\n", pindexPrev->nHeight, (unsigned int)pindexPrev->GetBlockTime());
281
+ return true;
282
+ }
283
+ if (nModifierTime / params.nModifierInterval >= pindexCurrent->GetBlockTime() / params.nModifierInterval)
284
+ {
285
+ // v0.4+ requires current block timestamp also be in a different modifier interval
286
+ if (IsProtocolV04(pindexCurrent->nTime))
287
+ {
288
+ if (gArgs.GetBoolArg("-debug", false))
289
+ LogPrintf("ComputeNextStakeModifier: (v0.4+) no new interval keep current modifier: pindexCurrent nHeight=%d nTime=%u\n", pindexCurrent->nHeight, (unsigned int)pindexCurrent->GetBlockTime());
290
+ return true;
291
+ }
292
+ else
293
+ {
294
+ if (gArgs.GetBoolArg("-debug", false))
295
+ LogPrintf("ComputeNextStakeModifier: v0.3 modifier at block %s not meeting v0.4+ protocol: pindexCurrent nHeight=%d nTime=%u\n", pindexCurrent->GetBlockHash().ToString(), pindexCurrent->nHeight, (unsigned int)pindexCurrent->GetBlockTime());
296
+ }
297
+ }
298
+
299
+ // Sort candidate blocks by timestamp
300
+ vector<pair<int64_t, uint256> > vSortedByTimestamp;
301
+ vSortedByTimestamp.reserve(64 * params.nModifierInterval / params.nStakeTargetSpacing);
302
+ int64_t nSelectionInterval = GetStakeModifierSelectionInterval();
303
+ int64_t nSelectionIntervalStart = (pindexPrev->GetBlockTime() / params.nModifierInterval) * params.nModifierInterval - nSelectionInterval;
304
+ const CBlockIndex* pindex = pindexPrev;
305
+ while (pindex && pindex->GetBlockTime() >= nSelectionIntervalStart)
306
+ {
307
+ vSortedByTimestamp.push_back(make_pair(pindex->GetBlockTime(), pindex->GetBlockHash()));
308
+ pindex = pindex->pprev;
309
+ }
310
+ int nHeightFirstCandidate = pindex ? (pindex->nHeight + 1) : 0;
311
+
312
+ // Shuffle before sort
313
+ for(int i = vSortedByTimestamp.size() - 1; i > 1; --i)
314
+ std::swap(vSortedByTimestamp[i], vSortedByTimestamp[GetRand(i)]);
315
+
316
+ sort(vSortedByTimestamp.begin(), vSortedByTimestamp.end(), [] (const pair<int64_t, uint256> &a, const pair<int64_t, uint256> &b)
317
+ {
318
+ if (a.first != b.first)
319
+ return a.first < b.first;
320
+ // Timestamp equals - compare block hashes
321
+ const uint32_t *pa = a.second.GetDataPtr();
322
+ const uint32_t *pb = b.second.GetDataPtr();
323
+ int cnt = 256 / 32;
324
+ do {
325
+ --cnt;
326
+ if (pa[cnt] != pb[cnt])
327
+ return pa[cnt] < pb[cnt];
328
+ } while(cnt);
329
+ return false; // Elements are equal
330
+ });
331
+
332
+ // Select 64 blocks from candidate blocks to generate stake modifier
333
+ uint64_t nStakeModifierNew = 0;
334
+ int64_t nSelectionIntervalStop = nSelectionIntervalStart;
335
+ map<uint256, const CBlockIndex*> mapSelectedBlocks;
336
+ for (int nRound=0; nRound<min(64, (int)vSortedByTimestamp.size()); nRound++)
337
+ {
338
+ // add an interval section to the current selection round
339
+ nSelectionIntervalStop += GetStakeModifierSelectionIntervalSection(nRound);
340
+ // select a block from the candidates of current round
341
+ if (!SelectBlockFromCandidates(vSortedByTimestamp, mapSelectedBlocks, nSelectionIntervalStop, nStakeModifier, &pindex, chainstate))
342
+ return error("ComputeNextStakeModifier: unable to select block at round %d", nRound);
343
+ // write the entropy bit of the selected block
344
+ nStakeModifierNew |= (((uint64_t)pindex->GetStakeEntropyBit()) << nRound);
345
+ // add the selected block from candidates to selected list
346
+ mapSelectedBlocks.insert(make_pair(pindex->GetBlockHash(), pindex));
347
+ if (gArgs.GetBoolArg("-debug", false) && gArgs.GetBoolArg("-printstakemodifier", false))
348
+ LogPrintf("ComputeNextStakeModifier: selected round %d stop=%s height=%d bit=%d\n",
349
+ nRound, FormatISO8601DateTime(nSelectionIntervalStop), pindex->nHeight, pindex->GetStakeEntropyBit());
350
+ }
351
+
352
+ // Print selection map for visualization of the selected blocks
353
+ if (gArgs.GetBoolArg("-debug", false) && gArgs.GetBoolArg("-printstakemodifier", false))
354
+ {
355
+ string strSelectionMap = "";
356
+ // '-' indicates proof-of-work blocks not selected
357
+ strSelectionMap.insert(0, pindexPrev->nHeight - nHeightFirstCandidate + 1, '-');
358
+ pindex = pindexPrev;
359
+ while (pindex && pindex->nHeight >= nHeightFirstCandidate)
360
+ {
361
+ // '=' indicates proof-of-stake blocks not selected
362
+ if (pindex->IsProofOfStake())
363
+ strSelectionMap.replace(pindex->nHeight - nHeightFirstCandidate, 1, "=");
364
+ pindex = pindex->pprev;
365
+ }
366
+ for (const auto& item : mapSelectedBlocks)
367
+ {
368
+ // 'S' indicates selected proof-of-stake blocks
369
+ // 'W' indicates selected proof-of-work blocks
370
+ strSelectionMap.replace(item.second->nHeight - nHeightFirstCandidate, 1, item.second->IsProofOfStake()? "S" : "W");
371
+ }
372
+ LogPrintf("ComputeNextStakeModifier: selection height [%d, %d] map %s\n", nHeightFirstCandidate, pindexPrev->nHeight, strSelectionMap);
373
+ }
374
+ if (gArgs.GetBoolArg("-debug", false))
375
+ LogPrintf("ComputeNextStakeModifier: new modifier=0x%016x time=%s\n", nStakeModifierNew, FormatISO8601DateTime(pindexPrev->GetBlockTime()));
376
+
377
+ nStakeModifier = nStakeModifierNew;
378
+ fGeneratedStakeModifier = true;
379
+ return true;
380
+ }
381
+
382
+ // V0.5: Stake modifier used to hash for a stake kernel is chosen as the stake
383
+ // modifier that is (nStakeMinAge minus a selection interval) earlier than the
384
+ // stake, thus at least a selection interval later than the coin generating the
385
+ // kernel, as the generating coin is from at least nStakeMinAge ago.
386
+ static bool GetKernelStakeModifierV05(CBlockIndex* pindexPrev, unsigned int nTimeTx, uint64_t& nStakeModifier, int& nStakeModifierHeight, int64_t& nStakeModifierTime, bool fPrintProofOfStake)
387
+ {
388
+ const Consensus::Params& params = Params().GetConsensus();
389
+ const CBlockIndex* pindex = pindexPrev;
390
+ nStakeModifierHeight = pindex->nHeight;
391
+ nStakeModifierTime = pindex->GetBlockTime();
392
+ int64_t nStakeModifierSelectionInterval = GetStakeModifierSelectionInterval();
393
+
394
+ if (nStakeModifierTime + params.nStakeMinAge - nStakeModifierSelectionInterval <= (int64_t) nTimeTx)
395
+ {
396
+ // Best block is still more than
397
+ // (nStakeMinAge minus a selection interval) older than kernel timestamp
398
+ if (fPrintProofOfStake)
399
+ return error("GetKernelStakeModifier() : best block %s at height %d too old for stake",
400
+ pindex->GetBlockHash().ToString(), pindex->nHeight);
401
+ else
402
+ return false;
403
+ }
404
+ // loop to find the stake modifier earlier by
405
+ // (nStakeMinAge minus a selection interval)
406
+ while (nStakeModifierTime + params.nStakeMinAge - nStakeModifierSelectionInterval >(int64_t) nTimeTx)
407
+ {
408
+ if (!pindex->pprev)
409
+ { // reached genesis block; should not happen
410
+ return error("GetKernelStakeModifier() : reached genesis block");
411
+ }
412
+ pindex = pindex->pprev;
413
+ if (pindex->GeneratedStakeModifier())
414
+ {
415
+ nStakeModifierHeight = pindex->nHeight;
416
+ nStakeModifierTime = pindex->GetBlockTime();
417
+ }
418
+ }
419
+ nStakeModifier = pindex->nStakeModifier;
420
+ return true;
421
+ }
422
+
423
+ // V0.3: Stake modifier used to hash for a stake kernel is chosen as the stake
424
+ // modifier about a selection interval later than the coin generating the kernel
425
+ static bool GetKernelStakeModifierV03(CBlockIndex* pindexPrev, uint256 hashBlockFrom, uint64_t& nStakeModifier, int& nStakeModifierHeight, int64_t& nStakeModifierTime, bool fPrintProofOfStake, CChainState& chainstate)
426
+ {
427
+ const Consensus::Params& params = Params().GetConsensus();
428
+ nStakeModifier = 0;
429
+
430
+ const CBlockIndex* pindexFrom = chainstate.m_blockman.LookupBlockIndex(hashBlockFrom);
431
+ if (!pindexFrom)
432
+ return error("GetKernelStakeModifier() : block not indexed");
433
+
434
+ nStakeModifierHeight = pindexFrom->nHeight;
435
+ nStakeModifierTime = pindexFrom->GetBlockTime();
436
+ int64_t nStakeModifierSelectionInterval = GetStakeModifierSelectionInterval();
437
+
438
+
439
+ // we need to iterate index forward but we cannot depend on chainActive.Next()
440
+ // because there is no guarantee that we are checking blocks in active chain.
441
+ // So, we construct a temporary chain that we will iterate over.
442
+ // pindexFrom - this block contains coins that are used to generate PoS
443
+ // pindexPrev - this is a block that is previous to PoS block that we are checking, you can think of it as tip of our chain
444
+ std::vector<CBlockIndex*> tmpChain;
445
+ int32_t nDepth = pindexPrev->nHeight - (pindexFrom->nHeight-1); // -1 is used to also include pindexFrom
446
+ tmpChain.reserve(nDepth);
447
+ CBlockIndex* it = pindexPrev;
448
+ for (int i=1; i<=nDepth && !chainstate.m_chain.Contains(it); i++) {
449
+ tmpChain.push_back(it);
450
+ it = it->pprev;
451
+ }
452
+ std::reverse(tmpChain.begin(), tmpChain.end());
453
+ size_t n = 0;
454
+
455
+ const CBlockIndex* pindex = pindexFrom;
456
+ // loop to find the stake modifier later by a selection interval
457
+ while (nStakeModifierTime < pindexFrom->GetBlockTime() + nStakeModifierSelectionInterval)
458
+ {
459
+ const CBlockIndex* old_pindex = pindex;
460
+ pindex = (!tmpChain.empty() && pindex->nHeight >= tmpChain[0]->nHeight - 1)? tmpChain[n++] : chainstate.m_chain.Next(pindex);
461
+ if (n > tmpChain.size() || pindex == NULL) // check if tmpChain[n+1] exists
462
+ { // reached best block; may happen if node is behind on block chain
463
+ if (fPrintProofOfStake || (old_pindex->GetBlockTime() + params.nStakeMinAge - nStakeModifierSelectionInterval > GetAdjustedTime()))
464
+ return error("GetKernelStakeModifier() : reached best block %s at height %d from block %s",
465
+ old_pindex->GetBlockHash().ToString(), old_pindex->nHeight, hashBlockFrom.ToString());
466
+ else
467
+ return false;
468
+ }
469
+ if (pindex->GeneratedStakeModifier())
470
+ {
471
+ nStakeModifierHeight = pindex->nHeight;
472
+ nStakeModifierTime = pindex->GetBlockTime();
473
+ }
474
+ }
475
+ nStakeModifier = pindex->nStakeModifier;
476
+ return true;
477
+ }
478
+
479
+ // Get the stake modifier specified by the protocol to hash for a stake kernel
480
+ static bool GetKernelStakeModifier(CBlockIndex* pindexPrev, uint256 hashBlockFrom, unsigned int nTimeTx, uint64_t& nStakeModifier, int& nStakeModifierHeight, int64_t& nStakeModifierTime, bool fPrintProofOfStake, CChainState& chainstate)
481
+ {
482
+ if (IsProtocolV05(nTimeTx))
483
+ return GetKernelStakeModifierV05(pindexPrev, nTimeTx, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake);
484
+ else
485
+ return GetKernelStakeModifierV03(pindexPrev, hashBlockFrom, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake, chainstate);
486
+ }
487
+
488
+ // peercoin kernel protocol
489
+ // coinstake must meet hash target according to the protocol:
490
+ // kernel (input 0) must meet the formula
491
+ // hash(nStakeModifier + txPrev.block.nTime + txPrev.offset + txPrev.nTime + txPrev.vout.n + nTime) < bnTarget * nCoinDayWeight
492
+ // this ensures that the chance of getting a coinstake is proportional to the
493
+ // amount of coin age one owns.
494
+ // The reason this hash is chosen is the following:
495
+ // nStakeModifier:
496
+ // (v0.5) uses dynamic stake modifier around 21 days before the kernel,
497
+ // versus static stake modifier about 9 days after the staked
498
+ // coin (txPrev) used in v0.3
499
+ // (v0.3) scrambles computation to make it very difficult to precompute
500
+ // future proof-of-stake at the time of the coin's confirmation
501
+ // (v0.2) nBits (deprecated): encodes all past block timestamps
502
+ // txPrev.block.nTime: prevent nodes from guessing a good timestamp to
503
+ // generate transaction for future advantage
504
+ // txPrev.offset: offset of txPrev inside block, to reduce the chance of
505
+ // nodes generating coinstake at the same time
506
+ // txPrev.nTime: reduce the chance of nodes generating coinstake at the same
507
+ // time
508
+ // txPrev.vout.n: output number of txPrev, to reduce the chance of nodes
509
+ // generating coinstake at the same time
510
+ // block/tx hash should not be used here as they can be generated in vast
511
+ // quantities so as to generate blocks faster, degrading the system back into
512
+ // a proof-of-work situation.
513
+ //
514
+ bool CheckStakeKernelHash(unsigned int nBits, CBlockIndex* pindexPrev, const CBlockHeader& blockFrom, unsigned int nTxPrevOffset, const CTransactionRef& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, bool fPrintProofOfStake, CChainState& chainstate)
515
+ {
516
+ const Consensus::Params& params = Params().GetConsensus();
517
+ unsigned int nTimeBlockFrom = blockFrom.GetBlockTime();
518
+
519
+ if (nTimeTx < (txPrev->nTime? txPrev->nTime : nTimeBlockFrom)) // Transaction timestamp violation
520
+ return error("CheckStakeKernelHash() : nTime violation");
521
+
522
+ if (nTimeBlockFrom + params.nStakeMinAge > nTimeTx) // Min age requirement
523
+ return error("CheckStakeKernelHash() : min age violation");
524
+
525
+ CBigNum bnTargetPerCoinDay;
526
+ bnTargetPerCoinDay.SetCompact(nBits);
527
+ int64_t nValueIn = txPrev->vout[prevout.n].nValue;
528
+ // v0.3 protocol kernel hash weight starts from 0 at the 30-day min age
529
+ // this change increases active coins participating the hash and helps
530
+ // to secure the network when proof-of-stake difficulty is low
531
+ int64_t nTimeWeight = min((int64_t)nTimeTx - (txPrev->nTime? txPrev->nTime : nTimeBlockFrom), params.nStakeMaxAge) - (IsProtocolV03(nTimeTx)? params.nStakeMinAge : 0);
532
+ CBigNum bnCoinDayWeight = CBigNum(nValueIn) * nTimeWeight / COIN / (24 * 60 * 60);
533
+ // Calculate hash
534
+ CDataStream ss(SER_GETHASH, 0);
535
+ uint64_t nStakeModifier = 0;
536
+ int nStakeModifierHeight = 0;
537
+ int64_t nStakeModifierTime = 0;
538
+ if (IsProtocolV03(nTimeTx)) // v0.3 protocol
539
+ {
540
+ if (!GetKernelStakeModifier(pindexPrev, blockFrom.GetHash(), nTimeTx, nStakeModifier, nStakeModifierHeight, nStakeModifierTime, fPrintProofOfStake, chainstate))
541
+ return false;
542
+ ss << nStakeModifier;
543
+ }
544
+ else // v0.2 protocol
545
+ {
546
+ ss << nBits;
547
+ }
548
+
549
+ ss << nTimeBlockFrom << nTxPrevOffset << (txPrev->nTime? txPrev->nTime : nTimeBlockFrom) << prevout.n << nTimeTx;
550
+ hashProofOfStake = Hash(ss);
551
+ if (fPrintProofOfStake)
552
+ {
553
+ if (IsProtocolV03(nTimeTx)) {
554
+ const CBlockIndex* pindexTmp = chainstate.m_blockman.LookupBlockIndex(blockFrom.GetHash());
555
+ LogPrintf("CheckStakeKernelHash() : using modifier 0x%016x at height=%d timestamp=%s for block from height=%d timestamp=%s\n",
556
+ nStakeModifier, nStakeModifierHeight,
557
+ FormatISO8601DateTime(nStakeModifierTime),
558
+ pindexTmp->nHeight,
559
+ FormatISO8601DateTime(blockFrom.GetBlockTime()));
560
+ }
561
+ LogPrintf("CheckStakeKernelHash() : check protocol=%s modifier=0x%016x nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n",
562
+ IsProtocolV05(nTimeTx)? "0.5" : (IsProtocolV03(nTimeTx)? "0.3" : "0.2"),
563
+ IsProtocolV03(nTimeTx)? nStakeModifier : (uint64_t) nBits,
564
+ nTimeBlockFrom, nTxPrevOffset, (txPrev->nTime? txPrev->nTime : nTimeBlockFrom), prevout.n, nTimeTx,
565
+ hashProofOfStake.ToString());
566
+ }
567
+
568
+ // Now check if proof-of-stake hash meets target protocol
569
+ if (CBigNum(hashProofOfStake) > bnCoinDayWeight * bnTargetPerCoinDay)
570
+ return false;
571
+ if (gArgs.GetBoolArg("-debug", false) && !fPrintProofOfStake)
572
+ {
573
+ if (IsProtocolV03(nTimeTx)) {
574
+ const CBlockIndex* pindexTmp = chainstate.m_blockman.LookupBlockIndex(blockFrom.GetHash());
575
+ LogPrintf("CheckStakeKernelHash() : using modifier 0x%016x at height=%d timestamp=%s for block from height=%d timestamp=%s\n",
576
+ nStakeModifier, nStakeModifierHeight,
577
+ FormatISO8601DateTime(nStakeModifierTime),
578
+ pindexTmp->nHeight,
579
+ FormatISO8601DateTime(blockFrom.GetBlockTime()));
580
+ }
581
+ LogPrintf("CheckStakeKernelHash() : pass protocol=%s modifier=0x%016x nTimeBlockFrom=%u nTxPrevOffset=%u nTimeTxPrev=%u nPrevout=%u nTimeTx=%u hashProof=%s\n",
582
+ IsProtocolV03(nTimeTx)? "0.3" : "0.2",
583
+ IsProtocolV03(nTimeTx)? nStakeModifier : (uint64_t) nBits,
584
+ nTimeBlockFrom, nTxPrevOffset, (txPrev->nTime? txPrev->nTime : nTimeBlockFrom), prevout.n, nTimeTx,
585
+ hashProofOfStake.ToString());
586
+ }
587
+ return true;
588
+ }
589
+
590
+ // Check kernel hash target and coinstake signature
591
+ bool CheckProofOfStake(BlockValidationState &state, CBlockIndex* pindexPrev, const CTransactionRef& tx, unsigned int nBits, uint256& hashProofOfStake, unsigned int nTimeTx, CChainState& chainstate)
592
+ {
593
+ if (!tx->IsCoinStake())
594
+ return error("CheckProofOfStake() : called on non-coinstake %s", tx->GetHash().ToString());
595
+
596
+ // Kernel (input 0) must match the stake hash target per coin age (nBits)
597
+ const CTxIn& txin = tx->vin[0];
598
+
599
+ // Transaction index is required to get to block header
600
+ if (!g_txindex)
601
+ return error("CheckProofOfStake() : transaction index not available");
602
+
603
+ // Get transaction index for the previous transaction
604
+ CDiskTxPos postx;
605
+ if (!g_txindex->FindTxPosition(txin.prevout.hash, postx))
606
+ return error("CheckProofOfStake() : tx index not found"); // tx index not found
607
+
608
+ // Read txPrev and header of its block
609
+ CBlockHeader header;
610
+ CTransactionRef txPrev;
611
+ auto it = g_txindex->cachedTxs.find(txin.prevout.hash);
612
+ if (it != g_txindex->cachedTxs.end()) {
613
+ header = it->second.first;
614
+ txPrev = it->second.second;
615
+ } else {
616
+ CAutoFile file(node::OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
617
+ try {
618
+ file >> header;
619
+ fseek(file.Get(), postx.nTxOffset, SEEK_CUR);
620
+ file >> txPrev;
621
+ } catch (std::exception &e) {
622
+ return error("%s() : deserialize or I/O error in CheckProofOfStake()", __PRETTY_FUNCTION__);
623
+ }
624
+ //g_txindex->cachedTxs[txin.prevout.hash] = std::pair(header,txPrev);
625
+ }
626
+
627
+ if (txPrev->GetHash() != txin.prevout.hash)
628
+ return error("%s() : txid mismatch in CheckProofOfStake()", __PRETTY_FUNCTION__);
629
+
630
+ // Verify signature
631
+ {
632
+ int nIn = 0;
633
+ const CTxOut& prevOut = txPrev->vout[tx->vin[nIn].prevout.n];
634
+ TransactionSignatureChecker checker(&(*tx), nIn, prevOut.nValue, PrecomputedTransactionData(*tx), MissingDataBehavior(1));
635
+
636
+ if (!VerifyScript(tx->vin[nIn].scriptSig, prevOut.scriptPubKey, &(tx->vin[nIn].scriptWitness), SCRIPT_VERIFY_P2SH, checker, nullptr))
637
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "invalid-pos-script", strprintf("%s: VerifyScript failed on coinstake %s", __func__, tx->GetHash().ToString()));
638
+ }
639
+
640
+ if (!CheckStakeKernelHash(nBits, pindexPrev, header, postx.nTxOffset + CBlockHeader::NORMAL_SERIALIZE_SIZE, txPrev, txin.prevout, nTimeTx, hashProofOfStake, gArgs.GetBoolArg("-debug", false), chainstate))
641
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "check-kernel-failed", strprintf("CheckProofOfStake() : INFO: check kernel failed on coinstake %s, hashProof=%s", tx->GetHash().ToString(), hashProofOfStake.ToString())); // may occur during initial download or if behind on block chain sync
642
+
643
+ return true;
644
+ }
645
+
646
+ // Check whether the coinstake timestamp meets protocol
647
+ bool CheckCoinStakeTimestamp(int64_t nTimeBlock, int64_t nTimeTx)
648
+ {
649
+ if (IsProtocolV03(nTimeTx)) // v0.3 protocol
650
+ return (nTimeBlock == nTimeTx);
651
+ else // v0.2 protocol
652
+ return ((nTimeTx <= nTimeBlock) && (nTimeBlock <= nTimeTx + MAX_FUTURE_BLOCK_TIME_PREV9));
653
+ }
654
+
655
+ // Get stake modifier checksum
656
+ unsigned int GetStakeModifierChecksum(const CBlockIndex* pindex)
657
+ {
658
+ assert (pindex->pprev || pindex->GetBlockHash() == Params().GetConsensus().hashGenesisBlock);
659
+ // Hash previous checksum with flags, hashProofOfStake and nStakeModifier
660
+ CDataStream ss(SER_GETHASH, 0);
661
+ if (pindex->pprev)
662
+ ss << pindex->pprev->nStakeModifierChecksum;
663
+ ss << pindex->nFlags << pindex->hashProofOfStake << pindex->nStakeModifier;
664
+ arith_uint256 hashChecksum = UintToArith256(Hash(ss));
665
+ hashChecksum >>= (256 - 32);
666
+ return hashChecksum.GetLow64();
667
+ }
668
+
669
+ // Check stake modifier hard checkpoints
670
+ bool CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierChecksum)
671
+ {
672
+ bool fTestNet = Params().NetworkIDString() == CBaseChainParams::TESTNET;
673
+ if (fTestNet && mapStakeModifierTestnetCheckpoints.count(nHeight))
674
+ return nStakeModifierChecksum == mapStakeModifierTestnetCheckpoints[nHeight];
675
+
676
+ if (!fTestNet && mapStakeModifierCheckpoints.count(nHeight))
677
+ return nStakeModifierChecksum == mapStakeModifierCheckpoints[nHeight];
678
+
679
+ return true;
680
+ }
681
+
682
+ bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck)
683
+ {
684
+ return (HowSuperMajority(minVersion, pstart, nRequired, nToCheck) >= nRequired);
685
+ }
686
+
687
+ unsigned int HowSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck)
688
+ {
689
+ unsigned int nFound = 0;
690
+ for (unsigned int i = 0; i < nToCheck && nFound < nRequired && pstart != NULL; pstart = pstart->pprev )
691
+ {
692
+ if (!pstart->IsProofOfStake())
693
+ continue;
694
+
695
+ if (pstart->nVersion >= minVersion)
696
+ ++nFound;
697
+
698
+ i++;
699
+ }
700
+ return nFound;
701
+ }
702
+
703
+ // peercoin: entropy bit for stake modifier if chosen by modifier
704
+ unsigned int GetStakeEntropyBit(const CBlock& block)
705
+ {
706
+ unsigned int nEntropyBit = 0;
707
+ if (IsProtocolV04(block.nTime))
708
+ {
709
+ nEntropyBit = UintToArith256(block.GetHash()).GetLow64() & 1llu;// last bit of block hash
710
+ if (gArgs.GetBoolArg("-printstakemodifier", false))
711
+ LogPrintf("GetStakeEntropyBit(v0.4+): nTime=%u hashBlock=%s entropybit=%d\n", block.nTime, block.GetHash().ToString(), nEntropyBit);
712
+ }
713
+ else
714
+ {
715
+ // old protocol for entropy bit pre v0.4
716
+ uint160 hashSig = Hash160(block.vchBlockSig);
717
+ if (gArgs.GetBoolArg("-printstakemodifier", false))
718
+ LogPrintf("GetStakeEntropyBit(v0.3): nTime=%u hashSig=%s", block.nTime, hashSig.ToString());
719
+ nEntropyBit = hashSig.GetDataPtr()[4] >> 31; // take the first bit of the hash
720
+ if (gArgs.GetBoolArg("-printstakemodifier", false))
721
+ LogPrintf(" entropybit=%d\n", nEntropyBit);
722
+ }
723
+ return nEntropyBit;
724
+ }
725
+
src/kernel.h ADDED
@@ -0,0 +1,71 @@
1
+ // Copyright (c) 2012-2023 The Peercoin developers
2
+ // Distributed under the MIT software license, see the accompanying
3
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
+ #ifndef PEERCOIN_KERNEL_H
5
+ #define PEERCOIN_KERNEL_H
6
+
7
+ #include <primitives/transaction.h> // CTransaction(Ref)
8
+
9
+ class CBlockIndex;
10
+ class BlockValidationState;
11
+ class CBlockHeader;
12
+ class CBlock;
13
+ class CChainState;
14
+
15
+
16
+ // MODIFIER_INTERVAL_RATIO:
17
+ // ratio of group interval length between the last group and the first group
18
+ static const int MODIFIER_INTERVAL_RATIO = 3;
19
+
20
+ // Protocol switch time of v0.3 kernel protocol
21
+ extern unsigned int nProtocolV03SwitchTime;
22
+ extern unsigned int nProtocolV03TestSwitchTime;
23
+
24
+ // Whether a given coinstake is subject to new v0.3 protocol
25
+ bool IsProtocolV03(unsigned int nTimeCoinStake);
26
+ // Whether a given block is subject to new v0.4 protocol
27
+ bool IsProtocolV04(unsigned int nTimeBlock);
28
+ // Whether a given transaction is subject to new v0.5 protocol
29
+ bool IsProtocolV05(unsigned int nTimeTx);
30
+ // Whether a given block is subject to new v0.6 protocol
31
+ // Test against previous block index! (always available)
32
+ bool IsProtocolV06(const CBlockIndex *pindexPrev);
33
+ // Whether a given transaction is subject to new v0.7 protocol
34
+ bool IsProtocolV07(unsigned int nTimeTx);
35
+ // Whether a given block is subject to new BIPs from bitcoin 0.16.x
36
+ bool IsBTC16BIPsEnabled(uint32_t nTimeTx);
37
+ // Whether a given timestamp is subject to new v0.9 protocol
38
+ bool IsProtocolV09(unsigned int nTimeTx);
39
+ // Whether a given timestamp is subject to new v10 protocol
40
+ bool IsProtocolV10(unsigned int nTimeTx);
41
+ // Whether a given block is subject to new v12 protocol
42
+ bool IsProtocolV12(const CBlockIndex* pindexPrev);
43
+
44
+ // Compute the hash modifier for proof-of-stake
45
+ bool ComputeNextStakeModifier(const CBlockIndex* pindexCurrent, uint64_t& nStakeModifier, bool& fGeneratedStakeModifier, CChainState& chainstate);
46
+
47
+ // Check whether stake kernel meets hash target
48
+ // Sets hashProofOfStake on success return
49
+ bool CheckStakeKernelHash(unsigned int nBits, CBlockIndex* pindexPrev, const CBlockHeader& blockFrom, unsigned int nTxPrevOffset, const CTransactionRef& txPrev, const COutPoint& prevout, unsigned int nTimeTx, uint256& hashProofOfStake, bool fPrintProofOfStake, CChainState& chainstate);
50
+
51
+ // Check kernel hash target and coinstake signature
52
+ // Sets hashProofOfStake on success return
53
+ bool CheckProofOfStake(BlockValidationState &state, CBlockIndex* pindexPrev, const CTransactionRef &tx, unsigned int nBits, uint256& hashProofOfStake, unsigned int nTimeTx, CChainState& chainstate);
54
+
55
+ // Check whether the coinstake timestamp meets protocol
56
+ bool CheckCoinStakeTimestamp(int64_t nTimeBlock, int64_t nTimeTx);
57
+
58
+ // Get stake modifier checksum
59
+ unsigned int GetStakeModifierChecksum(const CBlockIndex* pindex);
60
+
61
+ // Check stake modifier hard checkpoints
62
+ bool CheckStakeModifierCheckpoints(int nHeight, unsigned int nStakeModifierChecksum);
63
+
64
+ // peercoin: block version supermajority calculation
65
+ bool IsSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck);
66
+ unsigned int HowSuperMajority(int minVersion, const CBlockIndex* pstart, unsigned int nRequired, unsigned int nToCheck);
67
+
68
+ // peercoin: entropy bit for stake modifier if chosen by modifier
69
+ unsigned int GetStakeEntropyBit(const CBlock& block);
70
+
71
+ #endif // PEERCOIN_KERNEL_H
src/kernelrecord.cpp ADDED
@@ -0,0 +1,120 @@
1
+ #include <kernelrecord.h>
2
+ #include <key_io.h>
3
+ #include <wallet/wallet.h>
4
+ #include <base58.h>
5
+ #include <chainparams.h>
6
+ #include <timedata.h>
7
+ #include <interfaces/wallet.h>
8
+ #include <math.h>
9
+ using namespace std;
10
+
11
+ bool KernelRecord::showTransaction(bool isCoinbase, int depth)
12
+ {
13
+ if (isCoinbase) {
14
+ if (depth < 2)
15
+ return false;
16
+ } else {
17
+ if (depth == 0)
18
+ return false;
19
+ }
20
+
21
+ return true;
22
+ }
23
+
24
+ /*
25
+ * Decompose CWallet transaction to model kernel records.
26
+ */
27
+ vector<KernelRecord> KernelRecord::decomposeOutput(interfaces::Wallet& wallet, const interfaces::WalletTx &wtx)
28
+ {
29
+ vector<KernelRecord> parts;
30
+ int64_t nTime = (wtx.tx->nTime ? wtx.tx->nTime : wtx.time);
31
+ uint256 hash = wtx.tx->GetHash();
32
+ std::map<std::string, std::string> mapValue = wtx.value_map;
33
+
34
+ int numBlocks;
35
+ interfaces::WalletTxStatus status;
36
+ interfaces::WalletOrderForm orderForm;
37
+ bool inMempool;
38
+ wallet.getWalletTxDetails(hash, status, orderForm, inMempool, numBlocks);
39
+
40
+ if (showTransaction(wtx.is_coinbase, status.depth_in_main_chain)) {
41
+ for (size_t nOut = 0; nOut < wtx.tx->vout.size(); nOut++) {
42
+ CTxOut txOut = wtx.tx->vout[nOut];
43
+ if (wallet.txoutIsMine(txOut)) {
44
+ CTxDestination address;
45
+ std::string addrStr;
46
+
47
+ if (ExtractDestination(txOut.scriptPubKey, address)) {
48
+ // Sent to Bitcoin Address
49
+ addrStr = EncodeDestination(address);
50
+ } else {
51
+ // Sent to IP, or other non-address transaction like OP_EVAL
52
+ addrStr = mapValue["to"];
53
+ }
54
+ std::vector<interfaces::WalletTxOut> coins = wallet.getCoins({COutPoint(hash, nOut)});
55
+ bool isSpent = coins.size() >= 1 ? coins[0].is_spent : true;
56
+ parts.push_back(KernelRecord(hash, nTime, addrStr, txOut.nValue, nOut, isSpent));
57
+ }
58
+ }
59
+ }
60
+
61
+ return parts;
62
+ }
63
+
64
+ std::string KernelRecord::getTxID()
65
+ {
66
+ return hash.ToString() + strprintf("-%03d", idx);
67
+ }
68
+
69
+ int64_t KernelRecord::getAge() const
70
+ {
71
+ return (GetAdjustedTime() - nTime) / 86400;
72
+ }
73
+
74
+ int64_t KernelRecord::getCoinAge() const
75
+ {
76
+ const Consensus::Params& params = Params().GetConsensus();
77
+ int nDayWeight = (min((GetAdjustedTime() - nTime), params.nStakeMaxAge) - params.nStakeMinAge) / 86400;
78
+ return max(nValue * nDayWeight / COIN, (int64_t) 0);
79
+ }
80
+
81
+ double KernelRecord::getProbToMintStake(double difficulty, int timeOffset) const
82
+ {
83
+ const Consensus::Params& params = Params().GetConsensus();
84
+ double maxTarget = pow(static_cast<double>(2), 224);
85
+ double target = maxTarget / difficulty;
86
+ int dayWeight = (min((GetAdjustedTime() - nTime) + timeOffset, params.nStakeMaxAge) - params.nStakeMinAge) / 86400;
87
+ uint64_t coinAge = max(nValue * dayWeight / COIN, (int64_t)0);
88
+ return target * coinAge / pow(static_cast<double>(2), 256);
89
+ }
90
+
91
+ double KernelRecord::getProbToMintWithinNMinutes(double difficulty, int minutes)
92
+ {
93
+ if(difficulty != prevDifficulty || minutes != prevMinutes)
94
+ {
95
+ double prob = 1;
96
+ double p;
97
+ int d = minutes / (60 * 24); // Number of full days
98
+ int m = minutes % (60 * 24); // Number of minutes in the last day
99
+ int i, timeOffset;
100
+
101
+ // Probabilities for the first d days
102
+ for(i = 0; i < d; i++)
103
+ {
104
+ timeOffset = i * 86400;
105
+ p = pow(1 - getProbToMintStake(difficulty, timeOffset), 86400);
106
+ prob *= p;
107
+ }
108
+
109
+ // Probability for the m minutes of the last day
110
+ timeOffset = d * 86400;
111
+ p = pow(1 - getProbToMintStake(difficulty, timeOffset), 60 * m);
112
+ prob *= p;
113
+
114
+ prob = 1 - prob;
115
+ prevProbability = prob;
116
+ prevDifficulty = difficulty;
117
+ prevMinutes = minutes;
118
+ }
119
+ return prevProbability;
120
+ }
src/kernelrecord.h ADDED
@@ -0,0 +1,60 @@
1
+ // Copyright (c) 2012-2023 The Peercoin developers
2
+ // Distributed under the MIT software license, see the accompanying
3
+ // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
+ #ifndef PEERCOIN_KERNELRECORD_H
5
+ #define PEERCOIN_KERNELRECORD_H
6
+
7
+ #include <uint256.h>
8
+ #include <interfaces/wallet.h>
9
+
10
+ namespace wallet {
11
+ class CWallet;
12
+ } // namespace wallet
13
+ //class CWallet;
14
+ using wallet::CWallet;
15
+ class CWalletTx;
16
+
17
+ class KernelRecord
18
+ {
19
+ public:
20
+ KernelRecord():
21
+ hash(), nTime(0), address(""), nValue(0), idx(0), spent(false), prevMinutes(0), prevDifficulty(0), prevProbability(0)
22
+ {
23
+ }
24
+
25
+ KernelRecord(uint256 hash, int64_t nTime):
26
+ hash(hash), nTime(nTime), address(""), nValue(0), idx(0), spent(false), prevMinutes(0), prevDifficulty(0), prevProbability(0)
27
+ {
28
+ }
29
+
30
+ KernelRecord(uint256 hash, int64_t nTime,
31
+ const std::string &address,
32
+ int64_t nValue, int idx, bool spent):
33
+ hash(hash), nTime(nTime), address(address), nValue(nValue),
34
+ idx(idx), spent(spent), prevMinutes(0), prevDifficulty(0), prevProbability(0)
35
+ {
36
+ }
37
+
38
+ static bool showTransaction(bool isCoinbase, int depth);
39
+ static std::vector<KernelRecord> decomposeOutput(interfaces::Wallet &wallet, const interfaces::WalletTx &wtx);
40
+
41
+
42
+ uint256 hash;
43
+ int64_t nTime;
44
+ std::string address;
45
+ int64_t nValue;
46
+ int idx;
47
+ bool spent;
48
+
49
+ std::string getTxID();
50
+ int64_t getAge() const;
51
+ int64_t getCoinAge() const;
52
+ double getProbToMintStake(double difficulty, int timeOffset = 0) const;
53
+ double getProbToMintWithinNMinutes(double difficulty, int minutes);
54
+ protected:
55
+ int prevMinutes;
56
+ double prevDifficulty;
57
+ double prevProbability;
58
+ };
59
+
60
+ #endif // PEERCOIN_KERNELRECORD_H
src/key.cpp CHANGED
@@ -243,7 +243,7 @@ bool CKey::VerifyPubKey(const CPubKey& pubkey) const {
243
243
  return false;
244
244
  }
245
245
  unsigned char rnd[8];
246
- std::string str = "Bitcoin key verification\n";
246
+ std::string str = "Peercoin key verification\n";
247
247
  GetRandBytes(rnd, sizeof(rnd));
248
248
  uint256 hash;
249
249
  CHash256().Write(MakeUCharSpan(str)).Write(rnd).Finalize(hash);
src/net.cpp CHANGED
@@ -118,6 +118,10 @@ std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(g_maplocalhost_mute
118
118
  static bool vfLimited[NET_MAX] GUARDED_BY(g_maplocalhost_mutex) = {};
119
119
  std::string strSubVersion;
120
120
 
121
+ // peercoin: temperature to measure how many PoS headers have been sent by this client
122
+ std::map<CNetAddr, int32_t> mapPoSTemperature;
123
+ std::set<std::pair<COutPoint, unsigned int>> setStakeSeen;
124
+
121
125
  void CConnman::AddAddrFetch(const std::string& strDest)
122
126
  {
123
127
  LOCK(m_addr_fetches_mutex);
@@ -3031,6 +3035,7 @@ CNode::CNode(NodeId idIn, ServiceFlags nLocalServicesIn, std::shared_ptr<Sock> s
3031
3035
  nLocalServices(nLocalServicesIn)
3032
3036
  {
3033
3037
  if (inbound_onion) assert(conn_type_in == ConnectionType::INBOUND);
3038
+ lastAcceptedHeader = uint256();
3034
3039
  if (conn_type_in != ConnectionType::BLOCK_RELAY) {
3035
3040
  m_tx_relay = std::make_unique<TxRelay>();
3036
3041
  }
src/net.h CHANGED
@@ -17,7 +17,6 @@
17
17
  #include <net_permissions.h>
18
18
  #include <netaddress.h>
19
19
  #include <netbase.h>
20
- #include <policy/feerate.h>
21
20
  #include <protocol.h>
22
21
  #include <random.h>
23
22
  #include <span.h>
@@ -88,6 +87,10 @@ static constexpr bool DEFAULT_FIXEDSEEDS{true};
88
87
  static const size_t DEFAULT_MAXRECEIVEBUFFER = 5 * 1000;
89
88
  static const size_t DEFAULT_MAXSENDBUFFER = 1 * 1000;
90
89
 
90
+ /** peercoin: Number of consecutive PoS headers are allowed from a single peer. Used to prevent out of memory attack. */
91
+ static const int32_t MAX_CONSECUTIVE_POS_HEADERS = 1000;
92
+
93
+ // const unsigned int POW_HEADER_COOLING = 70; - defined in protocol.cpp, so that it is visible to other files
91
94
  typedef int64_t NodeId;
92
95
 
93
96
  struct AddedNodeInfo
@@ -243,6 +246,8 @@ struct LocalServiceInfo {
243
246
 
244
247
  extern Mutex g_maplocalhost_mutex;
245
248
  extern std::map<CNetAddr, LocalServiceInfo> mapLocalHost GUARDED_BY(g_maplocalhost_mutex);
249
+ extern std::map<CNetAddr, int32_t> mapPoSTemperature;
250
+ extern std::set<std::pair<COutPoint, unsigned int>> setStakeSeen;
246
251
 
247
252
  extern const std::string NET_MESSAGE_COMMAND_OTHER;
248
253
  typedef std::map<std::string, uint64_t> mapMsgCmdSize; //command, total bytes
@@ -598,6 +603,8 @@ public:
598
603
  /** Lowest measured round-trip time. Used as an inbound peer eviction
599
604
  * criterium in CConnman::AttemptToEvictConnection. */
600
605
  std::atomic<std::chrono::microseconds> m_min_ping_time{std::chrono::microseconds::max()};
606
+ // peercoin: used to detect branch switches
607
+ uint256 lastAcceptedHeader;
601
608
 
602
609
  CNode(NodeId id, ServiceFlags nLocalServicesIn, std::shared_ptr<Sock> sock, const CAddress& addrIn, uint64_t nKeyedNetGroupIn, uint64_t nLocalHostNonceIn, const CAddress& addrBindIn, const std::string& addrNameIn, ConnectionType conn_type_in, bool inbound_onion);
603
610
  CNode(const CNode&) = delete;
@@ -959,6 +966,14 @@ public:
959
966
  /** Return true if we should disconnect the peer for failing an inactivity check. */
960
967
  bool ShouldRunInactivityChecks(const CNode& node, std::chrono::seconds now) const;
961
968
 
969
+ /**
970
+ * This is signaled when network activity should cease.
971
+ * A pointer to it is saved in `m_i2p_sam_session`, so make sure that
972
+ * the lifetime of `interruptNet` is not shorter than
973
+ * the lifetime of `m_i2p_sam_session`.
974
+ */
975
+ CThreadInterrupt interruptNet;
976
+
962
977
  private:
963
978
  struct ListenSocket {
964
979
  public:
@@ -1203,14 +1218,6 @@ private:
1203
1218
  Mutex mutexMsgProc;
1204
1219
  std::atomic<bool> flagInterruptMsgProc{false};
1205
1220
 
1206
- /**
1207
- * This is signaled when network activity should cease.
1208
- * A pointer to it is saved in `m_i2p_sam_session`, so make sure that
1209
- * the lifetime of `interruptNet` is not shorter than
1210
- * the lifetime of `m_i2p_sam_session`.
1211
- */
1212
- CThreadInterrupt interruptNet;
1213
-
1214
1221
  /**
1215
1222
  * I2P SAM session.
1216
1223
  * Used to accept incoming and make outgoing I2P connections.
src/net_processing.cpp CHANGED
@@ -9,17 +9,16 @@
9
9
  #include <banman.h>
10
10
  #include <blockencodings.h>
11
11
  #include <blockfilter.h>
12
+ #include <chain.h>
12
13
  #include <chainparams.h>
13
14
  #include <consensus/amount.h>
14
15
  #include <consensus/validation.h>
15
- #include <deploymentstatus.h>
16
16
  #include <hash.h>
17
17
  #include <index/blockfilterindex.h>
18
18
  #include <merkleblock.h>
19
19
  #include <netbase.h>
20
20
  #include <netmessagemaker.h>
21
21
  #include <node/blockstorage.h>
22
- #include <policy/fees.h>
23
22
  #include <policy/policy.h>
24
23
  #include <primitives/block.h>
25
24
  #include <primitives/transaction.h>
@@ -45,10 +44,11 @@
45
44
  #include <optional>
46
45
  #include <typeinfo>
47
46
 
47
+ #include <kernel.h>
48
+
48
49
  using node::ReadBlockFromDisk;
49
50
  using node::ReadRawBlockFromDisk;
50
51
  using node::fImporting;
51
- using node::fPruneMode;
52
52
  using node::fReindex;
53
53
 
54
54
  /** How long to cache transactions in mapRelay for normal relay */
@@ -415,7 +415,7 @@ private:
415
415
  void RelayAddress(NodeId originator, const CAddress& addr, bool fReachable);
416
416
 
417
417
  /** Send `feefilter` message. */
418
- void MaybeSendFeefilter(CNode& node, std::chrono::microseconds current_time) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
418
+ // void MaybeSendFeefilter(CNode& node, std::chrono::microseconds current_time) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
419
419
 
420
420
  const CChainParams& m_chainparams;
421
421
  CConnman& m_connman;
@@ -594,6 +594,13 @@ private:
594
594
  TxOrphanage m_orphanage;
595
595
 
596
596
  void AddToCompactExtraTransactions(const CTransactionRef& tx) EXCLUSIVE_LOCKS_REQUIRED(g_cs_orphans);
597
+ /** peercoin: blocks that are waiting to be processed, the key points to previous CBlockIndex entry */
598
+ struct WaitElement {
599
+ std::shared_ptr<CBlock> pblock;
600
+ int64_t time;
601
+ };
602
+ std::map<CBlockIndex*, WaitElement> mapBlocksWait;
603
+
597
604
 
598
605
  /** Orphan/conflicted/etc transactions that are kept for compact block reconstruction.
599
606
  * The last -blockreconstructionextratxn/DEFAULT_BLOCK_RECONSTRUCTION_EXTRA_TXN of
@@ -1004,8 +1011,8 @@ void PeerManagerImpl::ProcessBlockAvailability(NodeId nodeid) {
1004
1011
 
1005
1012
  if (!state->hashLastUnknownBlock.IsNull()) {
1006
1013
  const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(state->hashLastUnknownBlock);
1007
- if (pindex && pindex->nChainWork > 0) {
1008
- if (state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) {
1014
+ if (pindex && pindex->nChainTrust > 0) {
1015
+ if (state->pindexBestKnownBlock == nullptr || pindex->nChainTrust >= state->pindexBestKnownBlock->nChainTrust) {
1009
1016
  state->pindexBestKnownBlock = pindex;
1010
1017
  }
1011
1018
  state->hashLastUnknownBlock.SetNull();
@@ -1020,9 +1027,9 @@ void PeerManagerImpl::UpdateBlockAvailability(NodeId nodeid, const uint256 &hash
1020
1027
  ProcessBlockAvailability(nodeid);
1021
1028
 
1022
1029
  const CBlockIndex* pindex = m_chainman.m_blockman.LookupBlockIndex(hash);
1023
- if (pindex && pindex->nChainWork > 0) {
1030
+ if (pindex && pindex->nChainTrust > 0) {
1024
1031
  // An actually better block was announced.
1025
- if (state->pindexBestKnownBlock == nullptr || pindex->nChainWork >= state->pindexBestKnownBlock->nChainWork) {
1032
+ if (state->pindexBestKnownBlock == nullptr || pindex->nChainTrust >= state->pindexBestKnownBlock->nChainTrust) {
1026
1033
  state->pindexBestKnownBlock = pindex;
1027
1034
  }
1028
1035
  } else {
@@ -1043,7 +1050,7 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count
1043
1050
  // Make sure pindexBestKnownBlock is up to date, we'll need it.
1044
1051
  ProcessBlockAvailability(nodeid);
1045
1052
 
1046
- if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainWork < m_chainman.ActiveChain().Tip()->nChainWork || state->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
1053
+ if (state->pindexBestKnownBlock == nullptr || state->pindexBestKnownBlock->nChainTrust < m_chainman.ActiveChain().Tip()->nChainTrust || state->pindexBestKnownBlock->nChainTrust < nMinimumChainWork) {
1047
1054
  // This peer has nothing interesting.
1048
1055
  return;
1049
1056
  }
@@ -1060,7 +1067,6 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count
1060
1067
  if (state->pindexLastCommonBlock == state->pindexBestKnownBlock)
1061
1068
  return;
1062
1069
 
1063
- const Consensus::Params& consensusParams = m_chainparams.GetConsensus();
1064
1070
  std::vector<const CBlockIndex*> vToFetch;
1065
1071
  const CBlockIndex *pindexWalk = state->pindexLastCommonBlock;
1066
1072
  // Never fetch further than the best block we know the peer has, or more than BLOCK_DOWNLOAD_WINDOW + 1 beyond the last
@@ -1084,13 +1090,13 @@ void PeerManagerImpl::FindNextBlocksToDownload(NodeId nodeid, unsigned int count
1084
1090
  // Iterate over those blocks in vToFetch (in forward direction), adding the ones that
1085
1091
  // are not yet downloaded and not in flight to vBlocks. In the meantime, update
1086
1092
  // pindexLastCommonBlock as long as all ancestors are already downloaded, or if it's
1087
- // already part of our chain (and therefore don't need it even if pruned).
1093
+ // already part of our chain.
1088
1094
  for (const CBlockIndex* pindex : vToFetch) {
1089
1095
  if (!pindex->IsValid(BLOCK_VALID_TREE)) {
1090
1096
  // We consider the chain that this peer is on invalid.
1091
1097
  return;
1092
1098
  }
1093
- if (!State(nodeid)->fHaveWitness && DeploymentActiveAt(*pindex, consensusParams, Consensus::DEPLOYMENT_SEGWIT)) {
1099
+ if (!State(nodeid)->fHaveWitness && IsBTC16BIPsEnabled(pindex->nTime)) {
1094
1100
  // We wouldn't download this block or its descendants from this peer.
1095
1101
  return;
1096
1102
  }
@@ -1594,7 +1600,7 @@ void PeerManagerImpl::NewPoWValidBlock(const CBlockIndex *pindex, const std::sha
1594
1600
  return;
1595
1601
  nHighestFastAnnounce = pindex->nHeight;
1596
1602
 
1597
- bool fWitnessEnabled = DeploymentActiveAt(*pindex, m_chainparams.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT);
1603
+ bool fWitnessEnabled = IsBTC16BIPsEnabled(pindex->nTime);
1598
1604
  uint256 hashBlock(pblock->GetHash());
1599
1605
 
1600
1606
  {
@@ -1870,15 +1876,14 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
1870
1876
  pfrom.fDisconnect = true;
1871
1877
  return;
1872
1878
  }
1873
- // Pruned nodes may have deleted the block, so check whether
1874
- // it's available before trying to send.
1879
+ // Check whether the block is available before trying to send.
1875
1880
  if (!(pindex->nStatus & BLOCK_HAVE_DATA)) {
1876
1881
  return;
1877
1882
  }
1878
1883
  std::shared_ptr<const CBlock> pblock;
1879
1884
  if (a_recent_block && a_recent_block->GetHash() == pindex->GetBlockHash()) {
1880
1885
  pblock = a_recent_block;
1881
- } else if (inv.IsMsgWitnessBlk()) {
1886
+ } /* else if (inv.IsMsgWitnessBlk()) {
1882
1887
  // Fast-path: in this case it is possible to serve the block directly from disk,
1883
1888
  // as the network format matches the format on disk
1884
1889
  std::vector<uint8_t> block_data;
@@ -1887,7 +1892,7 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
1887
1892
  }
1888
1893
  m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::BLOCK, Span{block_data}));
1889
1894
  // Don't set pblock as we've sent the block
1890
- } else {
1895
+ } */ else {
1891
1896
  // Send block from disk
1892
1897
  std::shared_ptr<CBlock> pblockRead = std::make_shared<CBlock>();
1893
1898
  if (!ReadBlockFromDisk(*pblockRead, pindex, m_chainparams.GetConsensus())) {
@@ -1951,8 +1956,11 @@ void PeerManagerImpl::ProcessGetBlockData(CNode& pfrom, Peer& peer, const CInv&
1951
1956
  // Send immediately. This must send even if redundant,
1952
1957
  // and we want it right after the last block so they don't
1953
1958
  // wait for other stuff first.
1959
+ // peercoin: send latest proof-of-work block to allow the
1960
+ // download node to accept as orphan (proof-of-stake
1961
+ // block might be rejected by stake connection check)
1954
1962
  std::vector<CInv> vInv;
1955
- vInv.push_back(CInv(MSG_BLOCK, m_chainman.ActiveChain().Tip()->GetBlockHash()));
1963
+ vInv.push_back(CInv(MSG_BLOCK, GetLastBlockIndex(m_chainman.ActiveChain().Tip(), false)->GetBlockHash()));
1956
1964
  m_connman.PushMessage(&pfrom, msgMaker.Make(NetMsgType::INV, vInv));
1957
1965
  peer.m_continuation_block.SetNull();
1958
1966
  }
@@ -2164,13 +2172,15 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
2164
2172
  }
2165
2173
  }
2166
2174
 
2175
+ int32_t& nPoSTemperature = mapPoSTemperature[pfrom.addr];
2167
2176
  BlockValidationState state;
2168
- if (!m_chainman.ProcessNewBlockHeaders(headers, state, m_chainparams, &pindexLast)) {
2177
+ if (!m_chainman.ProcessNewBlockHeaders(nPoSTemperature, pfrom.lastAcceptedHeader, headers, state, m_chainparams, &pindexLast)) {
2169
2178
  if (state.IsInvalid()) {
2170
2179
  MaybePunishNodeForBlock(pfrom.GetId(), state, via_compact_block, "invalid header received");
2171
2180
  return;
2172
2181
  }
2173
2182
  }
2183
+ pfrom.lastAcceptedHeader = headers.back().GetHash();
2174
2184
 
2175
2185
  {
2176
2186
  LOCK(cs_main);
@@ -2187,7 +2197,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
2187
2197
  // because it is set in UpdateBlockAvailability. Some nullptr checks
2188
2198
  // are still present, however, as belt-and-suspenders.
2189
2199
 
2190
- if (received_new_header && pindexLast->nChainWork > m_chainman.ActiveChain().Tip()->nChainWork) {
2200
+ if (received_new_header && pindexLast->nChainTrust > m_chainman.ActiveChain().Tip()->nChainTrust) {
2191
2201
  nodestate->m_last_block_announcement = GetTime();
2192
2202
  }
2193
2203
 
@@ -2202,14 +2212,14 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
2202
2212
 
2203
2213
  // If this set of headers is valid and ends in a block with at least as
2204
2214
  // much work as our tip, download as much as possible.
2205
- if (CanDirectFetch() && pindexLast->IsValid(BLOCK_VALID_TREE) && m_chainman.ActiveChain().Tip()->nChainWork <= pindexLast->nChainWork) {
2215
+ if (CanDirectFetch() && pindexLast->IsValid(BLOCK_VALID_TREE) && m_chainman.ActiveChain().Tip()->nChainTrust <= pindexLast->nChainTrust) {
2206
2216
  std::vector<const CBlockIndex*> vToFetch;
2207
2217
  const CBlockIndex *pindexWalk = pindexLast;
2208
2218
  // Calculate all the blocks we'd need to switch to pindexLast, up to a limit.
2209
2219
  while (pindexWalk && !m_chainman.ActiveChain().Contains(pindexWalk) && vToFetch.size() <= MAX_BLOCKS_IN_TRANSIT_PER_PEER) {
2210
2220
  if (!(pindexWalk->nStatus & BLOCK_HAVE_DATA) &&
2211
2221
  !IsBlockRequested(pindexWalk->GetBlockHash()) &&
2212
- (!DeploymentActiveAt(*pindexWalk, m_chainparams.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT) || State(pfrom.GetId())->fHaveWitness)) {
2222
+ (!IsBTC16BIPsEnabled(pindexWalk->nTime) || State(pfrom.GetId())->fHaveWitness)) {
2213
2223
  // We don't have this block, and it's not yet in flight.
2214
2224
  vToFetch.push_back(pindexWalk);
2215
2225
  }
@@ -2259,7 +2269,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
2259
2269
  if (m_chainman.ActiveChainstate().IsInitialBlockDownload() && nCount != MAX_HEADERS_RESULTS) {
2260
2270
  // When nCount < MAX_HEADERS_RESULTS, we know we have no more
2261
2271
  // headers to fetch from this peer.
2262
- if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainWork < nMinimumChainWork) {
2272
+ if (nodestate->pindexBestKnownBlock && nodestate->pindexBestKnownBlock->nChainTrust < nMinimumChainWork) {
2263
2273
  // This peer has too little work on their headers chain to help
2264
2274
  // us sync -- disconnect if it is an outbound disconnection
2265
2275
  // candidate.
@@ -2281,7 +2291,7 @@ void PeerManagerImpl::ProcessHeadersMessage(CNode& pfrom, const Peer& peer,
2281
2291
  // thus always subject to eviction under the bad/lagging chain logic.
2282
2292
  // See ChainSyncTimeoutState.
2283
2293
  if (!pfrom.fDisconnect && pfrom.IsFullOutboundConn() && nodestate->pindexBestKnownBlock != nullptr) {
2284
- if (m_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainWork >= m_chainman.ActiveChain().Tip()->nChainWork && !nodestate->m_chain_sync.m_protect) {
2294
+ if (m_outbound_peers_with_protect_from_disconnect < MAX_OUTBOUND_PEERS_TO_PROTECT_FROM_DISCONNECT && nodestate->pindexBestKnownBlock->nChainTrust >= m_chainman.ActiveChain().Tip()->nChainTrust && !nodestate->m_chain_sync.m_protect) {
2285
2295
  LogPrint(BCLog::NET, "Protecting outbound peer=%d from eviction\n", pfrom.GetId());
2286
2296
  nodestate->m_chain_sync.m_protect = true;
2287
2297
  ++m_outbound_peers_with_protect_from_disconnect;
@@ -2560,9 +2570,17 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
2560
2570
  PeerRef peer = GetPeerRef(pfrom.GetId());
2561
2571
  if (peer == nullptr) return;
2562
2572
 
2573
+ // set deserialization mode to read PoS flag in headers
2574
+ vRecv.SetType(vRecv.GetType() | SER_POSMARKER);
2575
+
2563
2576
  if (msg_type == NetMsgType::VERSION) {
2564
- if (pfrom.nVersion != 0) {
2565
- LogPrint(BCLog::NET, "redundant version message from peer=%d\n", pfrom.GetId());
2577
+ auto it = mapPoSTemperature.find(pfrom.addr);
2578
+ if (it == mapPoSTemperature.end())
2579
+ mapPoSTemperature[pfrom.addr] = MAX_CONSECUTIVE_POS_HEADERS/4;
2580
+ // Each connection can only send one version message
2581
+ if (pfrom.nVersion != 0)
2582
+ {
2583
+ Misbehaving(pfrom.GetId(), 1, "redundant version message");
2566
2584
  return;
2567
2585
  }
2568
2586
 
@@ -3016,13 +3034,11 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3016
3034
  for (CInv& inv : vInv) {
3017
3035
  if (interruptMsgProc) return;
3018
3036
 
3019
- // Ignore INVs that don't match wtxidrelay setting.
3020
- // Note that orphan parent fetching always uses MSG_TX GETDATAs regardless of the wtxidrelay setting.
3021
- // This is fine as no INV messages are involved in that process.
3037
+ // ignore INVs that don't match wtxidrelay setting
3022
3038
  if (State(pfrom.GetId())->m_wtxid_relay) {
3023
- if (inv.IsMsgTx()) continue;
3039
+ if (inv.type == MSG_TX) continue;
3024
3040
  } else {
3025
- if (inv.IsMsgWtx()) continue;
3041
+ if (inv.type == MSG_WTX) continue;
3026
3042
  }
3027
3043
 
3028
3044
  if (inv.IsMsgBlk()) {
@@ -3134,14 +3150,10 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3134
3150
  if (pindex->GetBlockHash() == hashStop)
3135
3151
  {
3136
3152
  LogPrint(BCLog::NET, " getblocks stopping at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
3137
- break;
3138
- }
3139
- // If pruning, don't inv blocks unless we have on disk and are likely to still have
3140
- // for some reasonable time window (1 hour) that block relay might require.
3141
- const int nPrunedBlocksLikelyToHave = MIN_BLOCKS_TO_KEEP - 3600 / m_chainparams.GetConsensus().nPowTargetSpacing;
3142
- if (fPruneMode && (!(pindex->nStatus & BLOCK_HAVE_DATA) || pindex->nHeight <= m_chainman.ActiveChain().Tip()->nHeight - nPrunedBlocksLikelyToHave))
3143
- {
3144
- LogPrint(BCLog::NET, " getblocks stopping, pruned or too old block at %d %s\n", pindex->nHeight, pindex->GetBlockHash().ToString());
3153
+ // peercoin: tell downloading node about the latest block if it's
3154
+ // without risk being rejected due to stake connection check
3155
+ if (hashStop != m_chainman.ActiveChain().Tip()->GetBlockHash() && pindex->GetBlockTime() + Params().GetConsensus().nStakeMinAge > m_chainman.ActiveChain().Tip()->GetBlockTime())
3156
+ WITH_LOCK(peer->m_block_inv_mutex, peer->m_blocks_for_inv_relay.push_back(pindex->GetBlockHash()));
3145
3157
  break;
3146
3158
  }
3147
3159
  WITH_LOCK(peer->m_block_inv_mutex, peer->m_blocks_for_inv_relay.push_back(pindex->GetBlockHash()));
@@ -3517,15 +3529,24 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3517
3529
  }
3518
3530
  }
3519
3531
 
3532
+ int32_t& nPoSTemperature = mapPoSTemperature[pfrom.addr];
3520
3533
  const CBlockIndex *pindex = nullptr;
3521
3534
  BlockValidationState state;
3522
- if (!m_chainman.ProcessNewBlockHeaders({cmpctblock.header}, state, m_chainparams, &pindex)) {
3535
+ if (!m_chainman.ProcessNewBlockHeaders(nPoSTemperature, m_chainman.ActiveChain().Tip()->GetBlockHash(), {cmpctblock.header}, state, m_chainparams, &pindex)) {
3523
3536
  if (state.IsInvalid()) {
3524
3537
  MaybePunishNodeForBlock(pfrom.GetId(), state, /*via_compact_block*/ true, "invalid header via cmpctblock");
3525
3538
  return;
3526
3539
  }
3527
3540
  }
3528
3541
 
3542
+ if (nPoSTemperature >= MAX_CONSECUTIVE_POS_HEADERS) {
3543
+ nPoSTemperature = (MAX_CONSECUTIVE_POS_HEADERS*3)/4;
3544
+ if (Params().NetworkIDString() != "test") {
3545
+ Misbehaving(pfrom.GetId(), 100, "too many consecutive pos headers");
3546
+ return;
3547
+ }
3548
+ }
3549
+
3529
3550
  // When we succeed in decoding a block's txids from a cmpctblock
3530
3551
  // message we typically jump to the BLOCKTXN handling code, with a
3531
3552
  // dummy (empty) BLOCKTXN message, to re-use the logic there in
@@ -3552,7 +3573,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3552
3573
 
3553
3574
  // If this was a new header with more work than our tip, update the
3554
3575
  // peer's last block announcement time
3555
- if (received_new_header && pindex->nChainWork > m_chainman.ActiveChain().Tip()->nChainWork) {
3576
+ if (received_new_header && pindex->nChainTrust > m_chainman.ActiveChain().Tip()->nChainTrust) {
3556
3577
  nodestate->m_last_block_announcement = GetTime();
3557
3578
  }
3558
3579
 
@@ -3562,8 +3583,8 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3562
3583
  if (pindex->nStatus & BLOCK_HAVE_DATA) // Nothing to do here
3563
3584
  return;
3564
3585
 
3565
- if (pindex->nChainWork <= m_chainman.ActiveChain().Tip()->nChainWork || // We know something better
3566
- pindex->nTx != 0) { // We had this block at some point, but pruned it
3586
+ if (pindex->nChainTrust <= m_chainman.ActiveChain().Tip()->nChainTrust || // We know something better
3587
+ pindex->nTx != 0) { // We had this block at some point
3567
3588
  if (fAlreadyInFlight) {
3568
3589
  // We requested this block for some reason, but our mempool will probably be useless
3569
3590
  // so we just grab the block via normal getdata
@@ -3579,7 +3600,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3579
3600
  return;
3580
3601
  }
3581
3602
 
3582
- if (DeploymentActiveAt(*pindex, m_chainparams.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT) && !nodestate->fSupportsDesiredCmpctVersion) {
3603
+ if (IsBTC16BIPsEnabled(pindex->nTime) && !nodestate->fSupportsDesiredCmpctVersion) {
3583
3604
  // Don't bother trying to process compact blocks from v1 peers
3584
3605
  // after segwit activates.
3585
3606
  return;
@@ -3797,9 +3818,32 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3797
3818
  return;
3798
3819
  }
3799
3820
  headers.resize(nCount);
3800
- for (unsigned int n = 0; n < nCount; n++) {
3801
- vRecv >> headers[n];
3802
- ReadCompactSize(vRecv); // ignore tx count; assume it is 0.
3821
+ {
3822
+ LOCK(cs_main);
3823
+ int32_t& nPoSTemperature = mapPoSTemperature[pfrom.addr];
3824
+ int nTmpPoSTemperature = nPoSTemperature;
3825
+ for (unsigned int n = 0; n < nCount; n++) {
3826
+ vRecv >> headers[n];
3827
+ ReadCompactSize(vRecv); // ignore tx count; assume it is 0.
3828
+ ReadCompactSize(vRecv); // needed for vchBlockSig.
3829
+
3830
+ // peercoin: quick check to see if we should ban peers for PoS spam
3831
+ // note: at this point we don't know if PoW headers are valid - we just assume they are
3832
+ // so we need to update pfrom->nPoSTemperature once we actualy check them
3833
+ bool fPoS = headers[n].nFlags & CBlockIndex::BLOCK_PROOF_OF_STAKE;
3834
+ nTmpPoSTemperature += fPoS ? 1 : -POW_HEADER_COOLING;
3835
+ // peer cannot cool himself by PoW headers from other branches
3836
+ if (n == 0 && !fPoS && headers[n].hashPrevBlock != pfrom.lastAcceptedHeader)
3837
+ nTmpPoSTemperature += POW_HEADER_COOLING;
3838
+ nTmpPoSTemperature = std::max(nTmpPoSTemperature, 0);
3839
+ if (nTmpPoSTemperature >= MAX_CONSECUTIVE_POS_HEADERS) {
3840
+ nPoSTemperature = (MAX_CONSECUTIVE_POS_HEADERS*3)/4;
3841
+ if (Params().NetworkIDString() != "test") {
3842
+ Misbehaving(pfrom.GetId(), 100, "too many consecutive pos headers");
3843
+ return;
3844
+ }
3845
+ }
3846
+ }
3803
3847
  }
3804
3848
 
3805
3849
  return ProcessHeadersMessage(pfrom, *peer, headers, /*via_compact_block=*/false);
@@ -3813,25 +3857,115 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
3813
3857
  return;
3814
3858
  }
3815
3859
 
3816
- std::shared_ptr<CBlock> pblock = std::make_shared<CBlock>();
3817
- vRecv >> *pblock;
3818
3860
 
3819
- LogPrint(BCLog::NET, "received block %s peer=%d\n", pblock->GetHash().ToString(), pfrom.GetId());
3861
+ std::shared_ptr<CBlock> pblock2 = std::make_shared<CBlock>();
3862
+ vRecv >> *pblock2;
3863
+ int64_t nTimeNow = GetTimeSeconds();
3864
+
3865
+ LogPrint(BCLog::NET, "received block %s peer=%d\n", pblock2->GetHash().ToString(), pfrom.GetId());
3820
3866
 
3821
- bool forceProcessing = false;
3822
- const uint256 hash(pblock->GetHash());
3823
3867
  {
3868
+ const uint256 hash2(pblock2->GetHash());
3824
3869
  LOCK(cs_main);
3825
- // Always process the block if we requested it, since we may
3826
- // need it even when it's not a candidate for a new best tip.
3827
- forceProcessing = IsBlockRequested(hash);
3828
- RemoveBlockRequest(hash);
3829
- // mapBlockSource is only used for punishing peers and setting
3830
- // which peers send us compact blocks, so the race between here and
3831
- // cs_main in ProcessNewBlock is fine.
3832
- mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true));
3833
- }
3834
- ProcessBlock(pfrom, pblock, forceProcessing);
3870
+ bool fRequested = mapBlocksInFlight.count(hash2);
3871
+
3872
+ CBlockIndex* headerPrev = m_chainman.m_blockman.LookupBlockIndex(pblock2->hashPrevBlock);
3873
+ if (!headerPrev) {
3874
+ LogPrint(BCLog::NET, "previous header not found");
3875
+ return;
3876
+ }
3877
+
3878
+ if (!fRequested) {
3879
+ int32_t& nPoSTemperature = mapPoSTemperature[pfrom.addr];
3880
+ if (nPoSTemperature >= MAX_CONSECUTIVE_POS_HEADERS) {
3881
+ nPoSTemperature = (MAX_CONSECUTIVE_POS_HEADERS*3)/4;
3882
+ if (Params().NetworkIDString() != "test") {
3883
+ Misbehaving(pfrom.GetId(), 100, "too many consecutive pos headers");
3884
+ return;
3885
+ }
3886
+ }
3887
+
3888
+ if (pblock2->IsProofOfStake() && !m_chainman.ActiveChainstate().IsInitialBlockDownload())
3889
+ nPoSTemperature += 1;
3890
+
3891
+ if (!headerPrev->IsValid(BLOCK_VALID_TRANSACTIONS)) {
3892
+ RemoveBlockRequest(hash2);
3893
+ LogPrint(BCLog::NET, "this block does not connect to any valid known blocks");
3894
+ return;
3895
+ }
3896
+ }
3897
+ // peercoin: store in memory until we can connect it to some chain
3898
+ WaitElement we; we.pblock = pblock2; we.time = nTimeNow;
3899
+ mapBlocksWait[headerPrev] = we;
3900
+ }
3901
+
3902
+ static CBlockIndex* pindexLastAccepted = nullptr;
3903
+ if (pindexLastAccepted == nullptr)
3904
+ pindexLastAccepted = m_chainman.ActiveChain().Tip();
3905
+ bool fContinue = true;
3906
+
3907
+ // peercoin: accept as many blocks as we possibly can from mapBlocksWait
3908
+ while (fContinue) {
3909
+ fContinue = false;
3910
+ bool fSelected = false;
3911
+ bool forceProcessing = false;
3912
+ CBlockIndex* pindexPrev;
3913
+ std::shared_ptr<CBlock> pblock;
3914
+
3915
+ {
3916
+ LOCK(cs_main);
3917
+ // peercoin: try to select next block in a constant time
3918
+ std::map<CBlockIndex*, WaitElement>::iterator it = mapBlocksWait.find(pindexLastAccepted);
3919
+ if (it != mapBlocksWait.end() && pindexLastAccepted != nullptr) {
3920
+ pindexPrev = it->first;
3921
+ pblock = it->second.pblock;
3922
+ mapBlocksWait.erase(pindexPrev);
3923
+ fContinue = true;
3924
+ fSelected = true;
3925
+ } else
3926
+ // otherwise: try to scan for it
3927
+ for (auto& pair : mapBlocksWait) {
3928
+ pindexPrev = pair.first;
3929
+ pblock = pair.second.pblock;
3930
+ const uint256 hash(pblock->GetHash());
3931
+ // remove blocks that were not connected in 60 seconds
3932
+ if (nTimeNow > pair.second.time + 60) {
3933
+ mapBlocksWait.erase(pindexPrev);
3934
+ fContinue = true;
3935
+ RemoveBlockRequest(hash);
3936
+ break;
3937
+ }
3938
+ if (!pindexPrev->IsValid(BLOCK_VALID_TRANSACTIONS)) {
3939
+ if (pindexPrev->nStatus & BLOCK_FAILED_MASK) {
3940
+ mapBlocksWait.erase(pindexPrev); // prev block was rejected
3941
+ fContinue = true;
3942
+ RemoveBlockRequest(hash);
3943
+ break;
3944
+ }
3945
+ continue; // prev block was not (yet) accepted on disk, skip to next one
3946
+ }
3947
+
3948
+ mapBlocksWait.erase(pindexPrev);
3949
+ fContinue = true;
3950
+ fSelected = true;
3951
+ break;
3952
+ }
3953
+ if (!fSelected)
3954
+ continue;
3955
+
3956
+ const uint256 hash(pblock->GetHash());
3957
+ // Always process the block if we requested it, since we may
3958
+ // need it even when it's not a candidate for a new best tip.
3959
+ forceProcessing = IsBlockRequested(hash);
3960
+ RemoveBlockRequest(hash);
3961
+ // mapBlockSource is only used for punishing peers and setting
3962
+ // which peers send us compact blocks, so the race between here and
3963
+ // cs_main in ProcessNewBlock is fine.
3964
+ mapBlockSource.emplace(hash, std::make_pair(pfrom.GetId(), true));
3965
+ }
3966
+
3967
+ ProcessBlock(pfrom, pblock, forceProcessing);
3968
+ }
3835
3969
  return;
3836
3970
  }
3837
3971
 
@@ -4048,7 +4182,7 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
4048
4182
  if (pfrom.m_tx_relay != nullptr) {
4049
4183
  pfrom.m_tx_relay->minFeeFilter = newFeeFilter;
4050
4184
  }
4051
- LogPrint(BCLog::NET, "received: feefilter of %s from peer=%d\n", CFeeRate(newFeeFilter).ToString(), pfrom.GetId());
4185
+ LogPrint(BCLog::NET, "received: feefilter of %d satoshi from peer=%d\n", newFeeFilter, pfrom.GetId());
4052
4186
  }
4053
4187
  return;
4054
4188
  }
@@ -4083,7 +4217,6 @@ void PeerManagerImpl::ProcessMessage(CNode& pfrom, const std::string& msg_type,
4083
4217
  }
4084
4218
  return;
4085
4219
  }
4086
-
4087
4220
  // Ignore unknown commands for extensibility
4088
4221
  LogPrint(BCLog::NET, "Unknown command \"%s\" from peer=%d\n", SanitizeString(msg_type), pfrom.GetId());
4089
4222
  return;
@@ -4224,13 +4357,13 @@ void PeerManagerImpl::ConsiderEviction(CNode& pto, std::chrono::seconds time_in_
4224
4357
  // their chain has more work than ours, we should sync to it,
4225
4358
  // unless it's invalid, in which case we should find that out and
4226
4359
  // disconnect from them elsewhere).
4227
- if (state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= m_chainman.ActiveChain().Tip()->nChainWork) {
4360
+ if (state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainTrust >= m_chainman.ActiveChain().Tip()->nChainTrust) {
4228
4361
  if (state.m_chain_sync.m_timeout != 0s) {
4229
4362
  state.m_chain_sync.m_timeout = 0s;
4230
4363
  state.m_chain_sync.m_work_header = nullptr;
4231
4364
  state.m_chain_sync.m_sent_getheaders = false;
4232
4365
  }
4233
- } else if (state.m_chain_sync.m_timeout == 0s || (state.m_chain_sync.m_work_header != nullptr && state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainWork >= state.m_chain_sync.m_work_header->nChainWork)) {
4366
+ } else if (state.m_chain_sync.m_timeout == 0s || (state.m_chain_sync.m_work_header != nullptr && state.pindexBestKnownBlock != nullptr && state.pindexBestKnownBlock->nChainTrust >= state.m_chain_sync.m_work_header->nChainTrust)) {
4234
4367
  // Our best block known by this peer is behind our tip, and we're either noticing
4235
4368
  // that for the first time, OR this peer was able to catch up to some earlier point
4236
4369
  // where we checked against our tip.
@@ -4504,6 +4637,7 @@ void PeerManagerImpl::MaybeSendAddr(CNode& node, Peer& peer, std::chrono::micros
4504
4637
  }
4505
4638
  }
4506
4639
 
4640
+ /*
4507
4641
  void PeerManagerImpl::MaybeSendFeefilter(CNode& pto, std::chrono::microseconds current_time)
4508
4642
  {
4509
4643
  AssertLockHeld(cs_main);
@@ -4546,6 +4680,7 @@ void PeerManagerImpl::MaybeSendFeefilter(CNode& pto, std::chrono::microseconds c
4546
4680
  pto.m_tx_relay->m_next_send_feefilter = current_time + GetRandomDuration<std::chrono::microseconds>(MAX_FEEFILTER_CHANGE_DELAY);
4547
4681
  }
4548
4682
  }
4683
+ */
4549
4684
 
4550
4685
  namespace {
4551
4686
  class CompareInvMempoolOrder
@@ -4833,7 +4968,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
4833
4968
  if (fSendTrickle && pto->m_tx_relay->fSendMempool) {
4834
4969
  auto vtxinfo = m_mempool.infoAll();
4835
4970
  pto->m_tx_relay->fSendMempool = false;
4836
- const CFeeRate filterrate{pto->m_tx_relay->minFeeFilter.load()};
4971
+ CAmount filterrate = 0;
4837
4972
 
4838
4973
  LOCK(pto->m_tx_relay->cs_filter);
4839
4974
 
@@ -4841,9 +4976,9 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
4841
4976
  const uint256& hash = state.m_wtxid_relay ? txinfo.tx->GetWitnessHash() : txinfo.tx->GetHash();
4842
4977
  CInv inv(state.m_wtxid_relay ? MSG_WTX : MSG_TX, hash);
4843
4978
  pto->m_tx_relay->setInventoryTxToSend.erase(hash);
4844
- // Don't send transactions that peers will not put into their mempool
4845
- if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
4846
- continue;
4979
+ if (filterrate) {
4980
+ if (txinfo.fee < filterrate)
4981
+ continue;
4847
4982
  }
4848
4983
  if (pto->m_tx_relay->pfilter) {
4849
4984
  if (!pto->m_tx_relay->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
@@ -4867,7 +5002,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
4867
5002
  for (std::set<uint256>::iterator it = pto->m_tx_relay->setInventoryTxToSend.begin(); it != pto->m_tx_relay->setInventoryTxToSend.end(); it++) {
4868
5003
  vInvTx.push_back(it);
4869
5004
  }
4870
- const CFeeRate filterrate{pto->m_tx_relay->minFeeFilter.load()};
5005
+ CAmount filterrate = 0;
4871
5006
  // Topologically and fee-rate sort the inventory we send for privacy and priority reasons.
4872
5007
  // A heap is used so that not all items need sorting if only a few are being sent.
4873
5008
  CompareInvMempoolOrder compareInvMempoolOrder(&m_mempool, state.m_wtxid_relay);
@@ -4897,7 +5032,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
4897
5032
  auto txid = txinfo.tx->GetHash();
4898
5033
  auto wtxid = txinfo.tx->GetWitnessHash();
4899
5034
  // Peer told you to not send transactions at that feerate? Don't bother sending it.
4900
- if (txinfo.fee < filterrate.GetFee(txinfo.vsize)) {
5035
+ if (filterrate && txinfo.fee < filterrate) {
4901
5036
  continue;
4902
5037
  }
4903
5038
  if (pto->m_tx_relay->pfilter && !pto->m_tx_relay->pfilter->IsRelevantAndUpdate(*txinfo.tx)) continue;
@@ -5011,7 +5146,7 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
5011
5146
  NodeId staller = -1;
5012
5147
  FindNextBlocksToDownload(pto->GetId(), MAX_BLOCKS_IN_TRANSIT_PER_PEER - state.nBlocksInFlight, vToDownload, staller);
5013
5148
  for (const CBlockIndex *pindex : vToDownload) {
5014
- uint32_t nFetchFlags = GetFetchFlags(*pto);
5149
+ uint32_t nFetchFlags = IsBTC16BIPsEnabled(pindex->nTime) ? GetFetchFlags(*pto) : false;
5015
5150
  vGetData.push_back(CInv(MSG_BLOCK | nFetchFlags, pindex->GetBlockHash()));
5016
5151
  BlockRequested(pto->GetId(), *pindex);
5017
5152
  LogPrint(BCLog::NET, "Requesting block %s (%d) peer=%d\n", pindex->GetBlockHash().ToString(),
@@ -5051,11 +5186,8 @@ bool PeerManagerImpl::SendMessages(CNode* pto)
5051
5186
  }
5052
5187
  }
5053
5188
 
5054
-
5055
5189
  if (!vGetData.empty())
5056
5190
  m_connman.PushMessage(pto, msgMaker.Make(NetMsgType::GETDATA, vGetData));
5057
-
5058
- MaybeSendFeefilter(*pto, current_time);
5059
5191
  } // release cs_main
5060
5192
  return true;
5061
5193
  }
src/netmessagemaker.h CHANGED
@@ -19,7 +19,7 @@ public:
19
19
  {
20
20
  CSerializedNetMsg msg;
21
21
  msg.m_type = std::move(msg_type);
22
- CVectorWriter{ SER_NETWORK, nFlags | nVersion, msg.data, 0, std::forward<Args>(args)... };
22
+ CVectorWriter{ SER_NETWORK | SER_POSMARKER, nFlags | nVersion, msg.data, 0, std::forward<Args>(args)... };
23
23
  return msg;
24
24
  }
25
25
 
src/node/blockstorage.cpp CHANGED
@@ -11,6 +11,7 @@
11
11
  #include <flatfile.h>
12
12
  #include <fs.h>
13
13
  #include <hash.h>
14
+ #include <kernel.h>
14
15
  #include <pow.h>
15
16
  #include <reverse_iterator.h>
16
17
  #include <shutdown.h>
@@ -24,9 +25,6 @@
24
25
  namespace node {
25
26
  std::atomic_bool fImporting(false);
26
27
  std::atomic_bool fReindex(false);
27
- bool fHavePruned = false;
28
- bool fPruneMode = false;
29
- uint64_t nPruneTarget = 0;
30
28
 
31
29
  static FILE* OpenUndoFile(const FlatFilePos& pos, bool fReadOnly = false);
32
30
  static FlatFileSeq BlockFileSeq();
@@ -65,9 +63,11 @@ CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block)
65
63
  pindexNew->BuildSkip();
66
64
  }
67
65
  pindexNew->nTimeMax = (pindexNew->pprev ? std::max(pindexNew->pprev->nTimeMax, pindexNew->nTime) : pindexNew->nTime);
68
- pindexNew->nChainWork = (pindexNew->pprev ? pindexNew->pprev->nChainWork : 0) + GetBlockProof(*pindexNew);
66
+ if (block.nFlags & CBlockIndex::BLOCK_PROOF_OF_STAKE)
67
+ pindexNew->SetProofOfStake();
68
+ pindexNew->nChainTrust = (pindexNew->pprev ? pindexNew->pprev->nChainTrust : 0) + GetBlockTrust(*pindexNew);
69
69
  pindexNew->RaiseValidity(BLOCK_VALID_TREE);
70
- if (pindexBestHeader == nullptr || pindexBestHeader->nChainWork < pindexNew->nChainWork)
70
+ if (pindexBestHeader == nullptr || pindexBestHeader->nChainTrust < pindexNew->nChainTrust)
71
71
  pindexBestHeader = pindexNew;
72
72
 
73
73
  m_dirty_blockindex.insert(pindexNew);
@@ -75,122 +75,6 @@ CBlockIndex* BlockManager::AddToBlockIndex(const CBlockHeader& block)
75
75
  return pindexNew;
76
76
  }
77
77
 
78
- void BlockManager::PruneOneBlockFile(const int fileNumber)
79
- {
80
- AssertLockHeld(cs_main);
81
- LOCK(cs_LastBlockFile);
82
-
83
- for (const auto& entry : m_block_index) {
84
- CBlockIndex* pindex = entry.second;
85
- if (pindex->nFile == fileNumber) {
86
- pindex->nStatus &= ~BLOCK_HAVE_DATA;
87
- pindex->nStatus &= ~BLOCK_HAVE_UNDO;
88
- pindex->nFile = 0;
89
- pindex->nDataPos = 0;
90
- pindex->nUndoPos = 0;
91
- m_dirty_blockindex.insert(pindex);
92
-
93
- // Prune from m_blocks_unlinked -- any block we prune would have
94
- // to be downloaded again in order to consider its chain, at which
95
- // point it would be considered as a candidate for
96
- // m_blocks_unlinked or setBlockIndexCandidates.
97
- auto range = m_blocks_unlinked.equal_range(pindex->pprev);
98
- while (range.first != range.second) {
99
- std::multimap<CBlockIndex*, CBlockIndex*>::iterator _it = range.first;
100
- range.first++;
101
- if (_it->second == pindex) {
102
- m_blocks_unlinked.erase(_it);
103
- }
104
- }
105
- }
106
- }
107
-
108
- m_blockfile_info[fileNumber].SetNull();
109
- m_dirty_fileinfo.insert(fileNumber);
110
- }
111
-
112
- void BlockManager::FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight, int chain_tip_height)
113
- {
114
- assert(fPruneMode && nManualPruneHeight > 0);
115
-
116
- LOCK2(cs_main, cs_LastBlockFile);
117
- if (chain_tip_height < 0) {
118
- return;
119
- }
120
-
121
- // last block to prune is the lesser of (user-specified height, MIN_BLOCKS_TO_KEEP from the tip)
122
- unsigned int nLastBlockWeCanPrune = std::min((unsigned)nManualPruneHeight, chain_tip_height - MIN_BLOCKS_TO_KEEP);
123
- int count = 0;
124
- for (int fileNumber = 0; fileNumber < m_last_blockfile; fileNumber++) {
125
- if (m_blockfile_info[fileNumber].nSize == 0 || m_blockfile_info[fileNumber].nHeightLast > nLastBlockWeCanPrune) {
126
- continue;
127
- }
128
- PruneOneBlockFile(fileNumber);
129
- setFilesToPrune.insert(fileNumber);
130
- count++;
131
- }
132
- LogPrintf("Prune (Manual): prune_height=%d removed %d blk/rev pairs\n", nLastBlockWeCanPrune, count);
133
- }
134
-
135
- void BlockManager::FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, int prune_height, bool is_ibd)
136
- {
137
- LOCK2(cs_main, cs_LastBlockFile);
138
- if (chain_tip_height < 0 || nPruneTarget == 0) {
139
- return;
140
- }
141
- if ((uint64_t)chain_tip_height <= nPruneAfterHeight) {
142
- return;
143
- }
144
-
145
- unsigned int nLastBlockWeCanPrune{(unsigned)std::min(prune_height, chain_tip_height - static_cast<int>(MIN_BLOCKS_TO_KEEP))};
146
- uint64_t nCurrentUsage = CalculateCurrentUsage();
147
- // We don't check to prune until after we've allocated new space for files
148
- // So we should leave a buffer under our target to account for another allocation
149
- // before the next pruning.
150
- uint64_t nBuffer = BLOCKFILE_CHUNK_SIZE + UNDOFILE_CHUNK_SIZE;
151
- uint64_t nBytesToPrune;
152
- int count = 0;
153
-
154
- if (nCurrentUsage + nBuffer >= nPruneTarget) {
155
- // On a prune event, the chainstate DB is flushed.
156
- // To avoid excessive prune events negating the benefit of high dbcache
157
- // values, we should not prune too rapidly.
158
- // So when pruning in IBD, increase the buffer a bit to avoid a re-prune too soon.
159
- if (is_ibd) {
160
- // Since this is only relevant during IBD, we use a fixed 10%
161
- nBuffer += nPruneTarget / 10;
162
- }
163
-
164
- for (int fileNumber = 0; fileNumber < m_last_blockfile; fileNumber++) {
165
- nBytesToPrune = m_blockfile_info[fileNumber].nSize + m_blockfile_info[fileNumber].nUndoSize;
166
-
167
- if (m_blockfile_info[fileNumber].nSize == 0) {
168
- continue;
169
- }
170
-
171
- if (nCurrentUsage + nBuffer < nPruneTarget) { // are we below our target?
172
- break;
173
- }
174
-
175
- // don't prune files that could have a block within MIN_BLOCKS_TO_KEEP of the main chain's tip but keep scanning
176
- if (m_blockfile_info[fileNumber].nHeightLast > nLastBlockWeCanPrune) {
177
- continue;
178
- }
179
-
180
- PruneOneBlockFile(fileNumber);
181
- // Queue up the files for removal
182
- setFilesToPrune.insert(fileNumber);
183
- nCurrentUsage -= nBytesToPrune;
184
- count++;
185
- }
186
- }
187
-
188
- LogPrint(BCLog::PRUNE, "Prune: target=%dMiB actual=%dMiB diff=%dMiB max_prune_height=%d removed %d blk/rev pairs\n",
189
- nPruneTarget/1024/1024, nCurrentUsage/1024/1024,
190
- ((int64_t)nPruneTarget - (int64_t)nCurrentUsage)/1024/1024,
191
- nLastBlockWeCanPrune, count);
192
- }
193
-
194
78
  CBlockIndex* BlockManager::InsertBlockIndex(const uint256& hash)
195
79
  {
196
80
  AssertLockHeld(cs_main);
@@ -221,7 +105,7 @@ bool BlockManager::LoadBlockIndex(
221
105
  return false;
222
106
  }
223
107
 
224
- // Calculate nChainWork
108
+ // Calculate nChainTrust
225
109
  std::vector<std::pair<int, CBlockIndex*>> vSortedByHeight;
226
110
  vSortedByHeight.reserve(m_block_index.size());
227
111
  for (const std::pair<const uint256, CBlockIndex*>& item : m_block_index) {
@@ -253,13 +137,12 @@ bool BlockManager::LoadBlockIndex(
253
137
  for (const std::pair<int, CBlockIndex*>& item : vSortedByHeight) {
254
138
  if (ShutdownRequested()) return false;
255
139
  CBlockIndex* pindex = item.second;
256
- pindex->nChainWork = (pindex->pprev ? pindex->pprev->nChainWork : 0) + GetBlockProof(*pindex);
140
+ pindex->nChainTrust = (pindex->pprev ? pindex->pprev->nChainTrust : 0) + GetBlockTrust(*pindex);
257
141
  pindex->nTimeMax = (pindex->pprev ? std::max(pindex->pprev->nTimeMax, pindex->nTime) : pindex->nTime);
258
142
 
259
143
  // We can link the chain of blocks for which we've received transactions at some point, or
260
144
  // blocks that are assumed-valid on the basis of snapshot load (see
261
145
  // PopulateAndValidateSnapshot()).
262
- // Pruned nodes may have deleted the block.
263
146
  if (pindex->nTx > 0) {
264
147
  if (pindex->pprev) {
265
148
  if (pindex->pprev->nChainTx > 0) {
@@ -310,7 +193,7 @@ bool BlockManager::LoadBlockIndex(
310
193
  }
311
194
  }
312
195
  }
313
- if (pindex->nStatus & BLOCK_FAILED_MASK && (!chainman.m_best_invalid || pindex->nChainWork > chainman.m_best_invalid->nChainWork)) {
196
+ if (pindex->nStatus & BLOCK_FAILED_MASK && (!chainman.m_best_invalid || pindex->nChainTrust > chainman.m_best_invalid->nChainTrust)) {
314
197
  chainman.m_best_invalid = pindex;
315
198
  }
316
199
  if (pindex->pprev) {
@@ -318,6 +201,12 @@ bool BlockManager::LoadBlockIndex(
318
201
  }
319
202
  if (pindex->IsValid(BLOCK_VALID_TREE) && (pindexBestHeader == nullptr || CBlockIndexWorkComparator()(pindexBestHeader, pindex)))
320
203
  pindexBestHeader = pindex;
204
+
205
+ // peercoin: calculate stake modifier checksum
206
+ pindex->nStakeModifierChecksum = GetStakeModifierChecksum(pindex);
207
+ if (chainman.ActiveChain().Contains(pindex))
208
+ if (!CheckStakeModifierCheckpoints(pindex->nHeight, pindex->nStakeModifierChecksum))
209
+ return error("LoadBlockIndex() : Failed stake modifier checkpoint height=%d, modifier=0x%016llx", pindex->nHeight, pindex->nStakeModifier);
321
210
  }
322
211
 
323
212
  return true;
@@ -399,12 +288,6 @@ bool BlockManager::LoadBlockIndexDB(ChainstateManager& chainman)
399
288
  }
400
289
  }
401
290
 
402
- // Check whether we have ever pruned block & undo files
403
- m_block_tree_db->ReadFlag("prunedblockfiles", fHavePruned);
404
- if (fHavePruned) {
405
- LogPrintf("LoadBlockIndexDB(): Block files have previously been pruned\n");
406
- }
407
-
408
291
  // Check whether we need to continue reindexing
409
292
  bool fReindexing = false;
410
293
  m_block_tree_db->ReadReindexing(fReindexing);
@@ -427,55 +310,6 @@ CBlockIndex* BlockManager::GetLastCheckpoint(const CCheckpointData& data)
427
310
  return nullptr;
428
311
  }
429
312
 
430
- bool IsBlockPruned(const CBlockIndex* pblockindex)
431
- {
432
- AssertLockHeld(::cs_main);
433
- return (fHavePruned && !(pblockindex->nStatus & BLOCK_HAVE_DATA) && pblockindex->nTx > 0);
434
- }
435
-
436
- // If we're using -prune with -reindex, then delete block files that will be ignored by the
437
- // reindex. Since reindexing works by starting at block file 0 and looping until a blockfile
438
- // is missing, do the same here to delete any later block files after a gap. Also delete all
439
- // rev files since they'll be rewritten by the reindex anyway. This ensures that m_blockfile_info
440
- // is in sync with what's actually on disk by the time we start downloading, so that pruning
441
- // works correctly.
442
- void CleanupBlockRevFiles()
443
- {
444
- std::map<std::string, fs::path> mapBlockFiles;
445
-
446
- // Glob all blk?????.dat and rev?????.dat files from the blocks directory.
447
- // Remove the rev files immediately and insert the blk file paths into an
448
- // ordered map keyed by block file index.
449
- LogPrintf("Removing unusable blk?????.dat and rev?????.dat files for -reindex with -prune\n");
450
- fs::path blocksdir = gArgs.GetBlocksDirPath();
451
- for (fs::directory_iterator it(blocksdir); it != fs::directory_iterator(); it++) {
452
- const std::string path = fs::PathToString(it->path().filename());
453
- if (fs::is_regular_file(*it) &&
454
- path.length() == 12 &&
455
- path.substr(8,4) == ".dat")
456
- {
457
- if (path.substr(0, 3) == "blk") {
458
- mapBlockFiles[path.substr(3, 5)] = it->path();
459
- } else if (path.substr(0, 3) == "rev") {
460
- remove(it->path());
461
- }
462
- }
463
- }
464
-
465
- // Remove all block files that aren't part of a contiguous set starting at
466
- // zero by walking the ordered map (keys are block file indices) by
467
- // keeping a separate counter. Once we hit a gap (or if 0 doesn't exist)
468
- // start removing block files.
469
- int nContigCounter = 0;
470
- for (const std::pair<const std::string, fs::path>& item : mapBlockFiles) {
471
- if (LocaleIndependentAtoi<int>(item.first) == nContigCounter) {
472
- nContigCounter++;
473
- continue;
474
- }
475
- remove(item.second);
476
- }
477
- }
478
-
479
313
  CBlockFileInfo* BlockManager::GetBlockFileInfo(size_t n)
480
314
  {
481
315
  LOCK(cs_LastBlockFile);
@@ -576,16 +410,6 @@ uint64_t BlockManager::CalculateCurrentUsage()
576
410
  return retval;
577
411
  }
578
412
 
579
- void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune)
580
- {
581
- for (std::set<int>::iterator it = setFilesToPrune.begin(); it != setFilesToPrune.end(); ++it) {
582
- FlatFilePos pos(*it, 0);
583
- fs::remove(BlockFileSeq().FileName(pos));
584
- fs::remove(UndoFileSeq().FileName(pos));
585
- LogPrint(BCLog::BLOCKSTORE, "Prune: %s deleted blk/rev (%05u)\n", __func__, *it);
586
- }
587
- }
588
-
589
413
  static FlatFileSeq BlockFileSeq()
590
414
  {
591
415
  return FlatFileSeq(gArgs.GetBlocksDirPath(), "blk", gArgs.GetBoolArg("-fastprune", false) ? 0x4000 /* 16kb */ : BLOCKFILE_CHUNK_SIZE);
@@ -658,9 +482,6 @@ bool BlockManager::FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigne
658
482
  if (out_of_space) {
659
483
  return AbortNode("Disk space is too low!", _("Disk space is too low!"));
660
484
  }
661
- if (bytes_allocated != 0 && fPruneMode) {
662
- m_check_for_pruning = true;
663
- }
664
485
  }
665
486
 
666
487
  m_dirty_fileinfo.insert(nFile);
@@ -682,9 +503,6 @@ bool BlockManager::FindUndoPos(BlockValidationState& state, int nFile, FlatFileP
682
503
  if (out_of_space) {
683
504
  return AbortNode(state, "Disk space is too low!", _("Disk space is too low!"));
684
505
  }
685
- if (bytes_allocated != 0 && fPruneMode) {
686
- m_check_for_pruning = true;
687
- }
688
506
 
689
507
  return true;
690
508
  }
@@ -760,7 +578,7 @@ bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::P
760
578
  }
761
579
 
762
580
  // Check the header
763
- if (!CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) {
581
+ if (block.IsProofOfWork() && !CheckProofOfWork(block.GetHash(), block.nBits, consensusParams)) {
764
582
  return error("ReadBlockFromDisk: Errors in block header at %s", pos.ToString());
765
583
  }
766
584
 
@@ -769,6 +587,10 @@ bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::P
769
587
  return error("ReadBlockFromDisk: Errors in block solution at %s", pos.ToString());
770
588
  }
771
589
 
590
+ // Set flag if proof of stake
591
+ if (block.IsProofOfStake())
592
+ block.nFlags |= CBlockIndex::BLOCK_PROOF_OF_STAKE;
593
+
772
594
  return true;
773
595
  }
774
596
 
src/node/blockstorage.h CHANGED
@@ -44,13 +44,6 @@ static const unsigned int MAX_BLOCKFILE_SIZE = 0x8000000; // 128 MiB
44
44
 
45
45
  extern std::atomic_bool fImporting;
46
46
  extern std::atomic_bool fReindex;
47
- /** Pruning-related variables and constants */
48
- /** True if any block files have ever been pruned. */
49
- extern bool fHavePruned;
50
- /** True if we're running in -prune mode. */
51
- extern bool fPruneMode;
52
- /** Number of MiB of block files that we're trying to stay below. */
53
- extern uint64_t nPruneTarget;
54
47
 
55
48
  typedef std::unordered_map<uint256, CBlockIndex*, BlockHasher> BlockMap;
56
49
 
@@ -76,37 +69,9 @@ private:
76
69
  bool FindBlockPos(FlatFilePos& pos, unsigned int nAddSize, unsigned int nHeight, CChain& active_chain, uint64_t nTime, bool fKnown);
77
70
  bool FindUndoPos(BlockValidationState& state, int nFile, FlatFilePos& pos, unsigned int nAddSize);
78
71
 
79
- /* Calculate the block/rev files to delete based on height specified by user with RPC command pruneblockchain */
80
- void FindFilesToPruneManual(std::set<int>& setFilesToPrune, int nManualPruneHeight, int chain_tip_height);
81
-
82
- /**
83
- * Prune block and undo files (blk???.dat and rev???.dat) so that the disk space used is less than a user-defined target.
84
- * The user sets the target (in MB) on the command line or in config file. This will be run on startup and whenever new
85
- * space is allocated in a block or undo file, staying below the target. Changing back to unpruned requires a reindex
86
- * (which in this case means the blockchain must be re-downloaded.)
87
- *
88
- * Pruning functions are called from FlushStateToDisk when the m_check_for_pruning flag has been set.
89
- * Block and undo files are deleted in lock-step (when blk00003.dat is deleted, so is rev00003.dat.)
90
- * Pruning cannot take place until the longest chain is at least a certain length (CChainParams::nPruneAfterHeight).
91
- * Pruning will never delete a block within a defined distance (currently 288) from the active chain's tip.
92
- * The block index is updated by unsetting HAVE_DATA and HAVE_UNDO for any blocks that were stored in the deleted files.
93
- * A db flag records the fact that at least some block files have been pruned.
94
- *
95
- * @param[out] setFilesToPrune The set of file indices that can be unlinked will be returned
96
- */
97
- void FindFilesToPrune(std::set<int>& setFilesToPrune, uint64_t nPruneAfterHeight, int chain_tip_height, int prune_height, bool is_ibd);
98
-
99
72
  RecursiveMutex cs_LastBlockFile;
100
73
  std::vector<CBlockFileInfo> m_blockfile_info;
101
74
  int m_last_blockfile = 0;
102
- /** Global flag to indicate we should check to see if there are
103
- * block/undo files that should be deleted. Set on startup
104
- * or if we allocate more file space when we're in prune mode
105
- */
106
- bool m_check_for_pruning = false;
107
-
108
- /** Dirty block index entries. */
109
- std::set<CBlockIndex*> m_dirty_blockindex;
110
75
 
111
76
  /** Dirty block file entries. */
112
77
  std::set<int> m_dirty_fileinfo;
@@ -116,12 +81,13 @@ public:
116
81
 
117
82
  /**
118
83
  * All pairs A->B, where A (or one of its ancestors) misses transactions, but B has transactions.
119
- * Pruned nodes may have entries where B is missing data.
120
84
  */
121
85
  std::multimap<CBlockIndex*, CBlockIndex*> m_blocks_unlinked;
122
-
123
86
  std::unique_ptr<CBlockTreeDB> m_block_tree_db GUARDED_BY(::cs_main);
124
87
 
88
+ /** Dirty block index entries. */
89
+ std::set<CBlockIndex*> m_dirty_blockindex;
90
+
125
91
  bool WriteBlockIndexDB() EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
126
92
  bool LoadBlockIndexDB(ChainstateManager& chainman) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
127
93
 
@@ -141,9 +107,6 @@ public:
141
107
  /** Create a new block index entry for a given block hash */
142
108
  CBlockIndex* InsertBlockIndex(const uint256& hash) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
143
109
 
144
- //! Mark one block file as pruned (modify associated database entries)
145
- void PruneOneBlockFile(const int fileNumber) EXCLUSIVE_LOCKS_REQUIRED(cs_main);
146
-
147
110
  CBlockIndex* LookupBlockIndex(const uint256& hash) const EXCLUSIVE_LOCKS_REQUIRED(cs_main);
148
111
 
149
112
  /** Get block file info entry for one block file */
@@ -166,21 +129,11 @@ public:
166
129
  }
167
130
  };
168
131
 
169
- //! Check whether the block associated with this index entry is pruned or not.
170
- bool IsBlockPruned(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_REQUIRED(::cs_main);
171
-
172
- void CleanupBlockRevFiles();
173
-
174
132
  /** Open a block file (blk?????.dat) */
175
133
  FILE* OpenBlockFile(const FlatFilePos& pos, bool fReadOnly = false);
176
134
  /** Translation to a filesystem path */
177
135
  fs::path GetBlockPosFilename(const FlatFilePos& pos);
178
136
 
179
- /**
180
- * Actually unlink the specified files
181
- */
182
- void UnlinkPrunedFiles(const std::set<int>& setFilesToPrune);
183
-
184
137
  /** Functions for disk access for blocks */
185
138
  bool ReadBlockFromDisk(CBlock& block, const FlatFilePos& pos, const Consensus::Params& consensusParams);
186
139
  bool ReadBlockFromDisk(CBlock& block, const CBlockIndex* pindex, const Consensus::Params& consensusParams);
src/node/chainstate.cpp CHANGED
@@ -12,7 +12,6 @@ namespace node {
12
12
  std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
13
13
  ChainstateManager& chainman,
14
14
  CTxMemPool* mempool,
15
- bool fPruneMode,
16
15
  const Consensus::Params& consensus_params,
17
16
  bool fReindexChainState,
18
17
  int64_t nBlockTreeDBCache,
@@ -42,16 +41,11 @@ std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
42
41
 
43
42
  if (fReset) {
44
43
  pblocktree->WriteReindexing(true);
45
- //If we're reindexing in prune mode, wipe away unusable block files and all undo data files
46
- if (fPruneMode)
47
- CleanupBlockRevFiles();
48
44
  }
49
45
 
50
46
  if (shutdown_requested && shutdown_requested()) return ChainstateLoadingError::SHUTDOWN_PROBED;
51
47
 
52
- // LoadBlockIndex will load fHavePruned if we've ever removed a
53
- // block file from disk.
54
- // Note that it also sets fReindex based on the disk flag!
48
+ // Note that LoadBlockIndex also sets fReindex based on the disk flag!
55
49
  // From here on out fReindex and fReset mean something different!
56
50
  if (!chainman.LoadBlockIndex()) {
57
51
  if (shutdown_requested && shutdown_requested()) return ChainstateLoadingError::SHUTDOWN_PROBED;
@@ -63,12 +57,6 @@ std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
63
57
  return ChainstateLoadingError::ERROR_BAD_GENESIS_BLOCK;
64
58
  }
65
59
 
66
- // Check for changed -prune state. What we are concerned about is a user who has pruned blocks
67
- // in the past, but is now trying to run unpruned.
68
- if (fHavePruned && !fPruneMode) {
69
- return ChainstateLoadingError::ERROR_PRUNED_NEEDS_REINDEX;
70
- }
71
-
72
60
  // At this point blocktree args are consistent with what's on disk.
73
61
  // If we're not mid-reindex (based on disk + args), add a genesis block on disk
74
62
  // (otherwise we use the one already on disk).
src/node/chainstate.h CHANGED
@@ -19,7 +19,6 @@ namespace node {
19
19
  enum class ChainstateLoadingError {
20
20
  ERROR_LOADING_BLOCK_DB,
21
21
  ERROR_BAD_GENESIS_BLOCK,
22
- ERROR_PRUNED_NEEDS_REINDEX,
23
22
  ERROR_LOAD_GENESIS_BLOCK_FAILED,
24
23
  ERROR_CHAINSTATE_UPGRADE_FAILED,
25
24
  ERROR_REPLAYBLOCKS_FAILED,
@@ -58,7 +57,6 @@ enum class ChainstateLoadingError {
58
57
  std::optional<ChainstateLoadingError> LoadChainstate(bool fReset,
59
58
  ChainstateManager& chainman,
60
59
  CTxMemPool* mempool,
61
- bool fPruneMode,
62
60
  const Consensus::Params& consensus_params,
63
61
  bool fReindexChainState,
64
62
  int64_t nBlockTreeDBCache,
src/node/context.cpp CHANGED
@@ -9,7 +9,6 @@
9
9
  #include <interfaces/chain.h>
10
10
  #include <net.h>
11
11
  #include <net_processing.h>
12
- #include <policy/fees.h>
13
12
  #include <scheduler.h>
14
13
  #include <txmempool.h>
15
14
  #include <validation.h>
src/node/context.h CHANGED
@@ -10,21 +10,23 @@
10
10
  #include <memory>
11
11
  #include <vector>
12
12
 
13
+ #include <interfaces/init.h>
14
+ #include <interfaces/chain.h>
15
+ #include <interfaces/wallet.h>
16
+
13
17
  class ArgsManager;
14
18
  class BanMan;
15
19
  class AddrMan;
16
- class CBlockPolicyEstimator;
17
20
  class CConnman;
18
21
  class CScheduler;
19
22
  class CTxMemPool;
20
23
  class ChainstateManager;
21
24
  class PeerManager;
22
- namespace interfaces {
23
- class Chain;
24
- class ChainClient;
25
- class Init;
26
- class WalletLoader;
27
- } // namespace interfaces
25
+
26
+ using interfaces::Chain;
27
+ using interfaces::ChainClient;
28
+ using interfaces::Init;
29
+ using interfaces::WalletLoader;
28
30
 
29
31
  namespace node {
30
32
  //! NodeContext struct containing references to chain state and connection
@@ -43,7 +45,6 @@ struct NodeContext {
43
45
  std::unique_ptr<AddrMan> addrman;
44
46
  std::unique_ptr<CConnman> connman;
45
47
  std::unique_ptr<CTxMemPool> mempool;
46
- std::unique_ptr<CBlockPolicyEstimator> fee_estimator;
47
48
  std::unique_ptr<PeerManager> peerman;
48
49
  std::unique_ptr<ChainstateManager> chainman;
49
50
  std::unique_ptr<BanMan> banman;
src/node/interfaces.cpp CHANGED
@@ -6,7 +6,6 @@
6
6
  #include <banman.h>
7
7
  #include <chain.h>
8
8
  #include <chainparams.h>
9
- #include <deploymentstatus.h>
10
9
  #include <external_signer.h>
11
10
  #include <init.h>
12
11
  #include <interfaces/chain.h>
@@ -23,10 +22,7 @@
23
22
  #include <node/context.h>
24
23
  #include <node/transaction.h>
25
24
  #include <node/ui_interface.h>
26
- #include <policy/feerate.h>
27
- #include <policy/fees.h>
28
25
  #include <policy/policy.h>
29
- #include <policy/rbf.h>
30
26
  #include <policy/settings.h>
31
27
  #include <primitives/block.h>
32
28
  #include <primitives/transaction.h>
@@ -81,8 +77,8 @@ private:
81
77
  class NodeImpl : public Node
82
78
  {
83
79
  private:
84
- ChainstateManager& chainman() { return *Assert(m_context->chainman); }
85
80
  public:
81
+ ChainstateManager& chainman() override { return *Assert(m_context->chainman); }
86
82
  explicit NodeImpl(NodeContext& context) { setContext(&context); }
87
83
  void initLogging() override { InitLogging(*Assert(m_context->args)); }
88
84
  void initParameterInteraction() override { InitParameterInteraction(*Assert(m_context->args)); }
@@ -258,7 +254,6 @@ public:
258
254
  }
259
255
  }
260
256
  bool getNetworkActive() override { return m_context->connman && m_context->connman->GetNetworkActive(); }
261
- CFeeRate getDustRelayFee() override { return ::dustRelayFee; }
262
257
  UniValue executeRpc(const std::string& command, const UniValue& params, const std::string& uri) override
263
258
  {
264
259
  JSONRPCRequest req;
@@ -276,9 +271,9 @@ public:
276
271
  LOCK(::cs_main);
277
272
  return chainman().ActiveChainstate().CoinsTip().GetCoin(output, coin);
278
273
  }
279
- TransactionError broadcastTransaction(CTransactionRef tx, CAmount max_tx_fee, std::string& err_string) override
274
+ TransactionError broadcastTransaction(CTransactionRef tx, std::string& err_string) override
280
275
  {
281
- return BroadcastTransaction(*m_context, std::move(tx), err_string, max_tx_fee, /*relay=*/ true, /*wait_callback=*/ false);
276
+ return BroadcastTransaction(*m_context, std::move(tx), err_string, /*relay=*/ true, /*wait_callback=*/ false);
282
277
  }
283
278
  WalletLoader& walletLoader() override
284
279
  {
@@ -314,7 +309,9 @@ public:
314
309
  }
315
310
  std::unique_ptr<Handler> handleNotifyAlertChanged(NotifyAlertChangedFn fn) override
316
311
  {
317
- return MakeHandler(::uiInterface.NotifyAlertChanged_connect(fn));
312
+ return MakeHandler(::uiInterface.NotifyAlertChanged_connect([fn](const uint256 &hash, ChangeType status) {
313
+ fn(hash, status);
314
+ }));
318
315
  }
319
316
  std::unique_ptr<Handler> handleBannedListChanged(BannedListChangedFn fn) override
320
317
  {
@@ -452,8 +449,8 @@ public:
452
449
  class ChainImpl : public Chain
453
450
  {
454
451
  private:
455
- ChainstateManager& chainman() { return *Assert(m_node.chainman); }
456
452
  public:
453
+ ChainstateManager& chainman() override { return *Assert(m_node.chainman); }
457
454
  explicit ChainImpl(NodeContext& node) : m_node(node) {}
458
455
  std::optional<int> getHeight() override
459
456
  {
@@ -550,7 +547,7 @@ public:
550
547
  bool hasBlocks(const uint256& block_hash, int min_height, std::optional<int> max_height) override
551
548
  {
552
549
  // hasBlocks returns true if all ancestors of block_hash in specified
553
- // range have block data (are not pruned), false if any ancestors in
550
+ // range have block data, false if any ancestors in
554
551
  // specified range are missing data.
555
552
  //
556
553
  // For simplicity and robustness, min_height and max_height are only
@@ -566,12 +563,14 @@ public:
566
563
  }
567
564
  return false;
568
565
  }
566
+ /*
569
567
  RBFTransactionState isRBFOptIn(const CTransaction& tx) override
570
568
  {
571
569
  if (!m_node.mempool) return IsRBFOptInEmptyMempool(tx);
572
570
  LOCK(m_node.mempool->cs);
573
571
  return IsRBFOptIn(tx, *m_node.mempool);
574
572
  }
573
+ */
575
574
  bool isInMempool(const uint256& txid) override
576
575
  {
577
576
  if (!m_node.mempool) return false;
@@ -586,11 +585,10 @@ public:
586
585
  return it && (*it)->GetCountWithDescendants() > 1;
587
586
  }
588
587
  bool broadcastTransaction(const CTransactionRef& tx,
589
- const CAmount& max_tx_fee,
590
588
  bool relay,
591
589
  std::string& err_string) override
592
590
  {
593
- const TransactionError err = BroadcastTransaction(m_node, tx, err_string, max_tx_fee, relay, /*wait_callback*/ false);
591
+ const TransactionError err = BroadcastTransaction(m_node, tx, err_string, relay, /*wait_callback*/ false);
594
592
  // Chain clients only care about failures to accept the tx to the mempool. Disregard non-mempool related failures.
595
593
  // Note: this will need to be updated if BroadcastTransactions() is updated to return other non-mempool failures
596
594
  // that Chain clients do not need to know about.
@@ -623,6 +621,7 @@ public:
623
621
  entry, ancestors, limit_ancestor_count, limit_ancestor_size,
624
622
  limit_descendant_count, limit_descendant_size, unused_error_string);
625
623
  }
624
+ /*
626
625
  CFeeRate estimateSmartFee(int num_blocks, bool conservative, FeeCalculation* calc) override
627
626
  {
628
627
  if (!m_node.fee_estimator) return {};
@@ -641,11 +640,7 @@ public:
641
640
  CFeeRate relayMinFee() override { return ::minRelayTxFee; }
642
641
  CFeeRate relayIncrementalFee() override { return ::incrementalRelayFee; }
643
642
  CFeeRate relayDustFee() override { return ::dustRelayFee; }
644
- bool havePruned() override
645
- {
646
- LOCK(cs_main);
647
- return node::fHavePruned;
648
- }
643
+ */
649
644
  bool isReadyToBroadcast() override { return !node::fImporting && !node::fReindex && !isInitialBlockDownload(); }
650
645
  bool isInitialBlockDownload() override {
651
646
  return chainman().ActiveChainstate().IsInitialBlockDownload();
src/node/miner.cpp CHANGED
@@ -13,34 +13,53 @@
13
13
  #include <consensus/merkle.h>
14
14
  #include <consensus/tx_verify.h>
15
15
  #include <consensus/validation.h>
16
- #include <deploymentstatus.h>
17
- #include <policy/feerate.h>
18
16
  #include <policy/policy.h>
19
17
  #include <pow.h>
20
18
  #include <primitives/transaction.h>
19
+ #include <rpc/blockchain.h>
21
20
  #include <timedata.h>
21
+ #include <rpc/blockchain.h>
22
22
  #include <util/moneystr.h>
23
23
  #include <util/system.h>
24
+ #include <util/threadnames.h>
25
+ #include <util/translation.h>
24
26
  #include <validation.h>
27
+ #include <kernel.h>
28
+ #include <net.h>
29
+ #include <interfaces/chain.h>
30
+ #include <node/context.h>
31
+ #include <node/ui_interface.h>
32
+ #include <util/thread.h>
33
+ #include <validation.h>
34
+ #include <wallet/wallet.h>
35
+ #include <wallet/coincontrol.h>
36
+ #include <warnings.h>
37
+ #include <wallet/spend.h>
38
+ #include <wallet/wallet.h>
25
39
 
26
40
  #include <algorithm>
27
41
  #include <utility>
28
42
 
43
+ #include <boost/thread.hpp>
44
+
45
+ using wallet::CWallet;
46
+ using wallet::COutput;
47
+ using wallet::CCoinControl;
48
+ using wallet::ReserveDestination;
49
+
50
+ int64_t nLastCoinStakeSearchInterval = 0;
51
+ std::thread m_minter_thread;
52
+
29
53
  namespace node {
30
- int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
54
+ int64_t UpdateTime(CBlockHeader* pblock)
31
55
  {
32
56
  int64_t nOldTime = pblock->nTime;
33
- int64_t nNewTime = std::max(pindexPrev->GetMedianTimePast() + 1, GetAdjustedTime());
57
+ int64_t nNewTime = std::max(pblock->GetBlockTime(), GetAdjustedTime());
34
58
 
35
59
  if (nOldTime < nNewTime) {
36
60
  pblock->nTime = nNewTime;
37
61
  }
38
62
 
39
- // Updating time can change work required on testnet:
40
- if (consensusParams.fPowAllowMinDifficultyBlocks) {
41
- pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, consensusParams);
42
- }
43
-
44
63
  return nNewTime - nOldTime;
45
64
  }
46
65
 
@@ -58,7 +77,6 @@ void RegenerateCommitments(CBlock& block, ChainstateManager& chainman)
58
77
 
59
78
  BlockAssembler::Options::Options()
60
79
  {
61
- blockMinFeeRate = CFeeRate(DEFAULT_BLOCK_MIN_TX_FEE);
62
80
  nBlockMaxWeight = DEFAULT_BLOCK_MAX_WEIGHT;
63
81
  }
64
82
 
@@ -67,7 +85,6 @@ BlockAssembler::BlockAssembler(CChainState& chainstate, const CTxMemPool& mempoo
67
85
  m_mempool(mempool),
68
86
  m_chainstate(chainstate)
69
87
  {
70
- blockMinFeeRate = options.blockMinFeeRate;
71
88
  // Limit weight to between 4K and MAX_BLOCK_WEIGHT-4K for sanity:
72
89
  nBlockMaxWeight = std::max<size_t>(4000, std::min<size_t>(MAX_BLOCK_WEIGHT - 4000, options.nBlockMaxWeight));
73
90
  }
@@ -78,12 +95,6 @@ static BlockAssembler::Options DefaultOptions()
78
95
  // If -blockmaxweight is not given, limit to DEFAULT_BLOCK_MAX_WEIGHT
79
96
  BlockAssembler::Options options;
80
97
  options.nBlockMaxWeight = gArgs.GetIntArg("-blockmaxweight", DEFAULT_BLOCK_MAX_WEIGHT);
81
- if (gArgs.IsArgSet("-blockmintxfee")) {
82
- std::optional<CAmount> parsed = ParseMoney(gArgs.GetArg("-blockmintxfee", ""));
83
- options.blockMinFeeRate = CFeeRate{parsed.value_or(DEFAULT_BLOCK_MIN_TX_FEE)};
84
- } else {
85
- options.blockMinFeeRate = CFeeRate{DEFAULT_BLOCK_MIN_TX_FEE};
86
- }
87
98
  return options;
88
99
  }
89
100
 
@@ -104,7 +115,8 @@ void BlockAssembler::resetBlock()
104
115
  nFees = 0;
105
116
  }
106
117
 
107
- std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn)
118
+ // peercoin: if pwallet != NULL it will attempt to create coinstake
119
+ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet, bool* pfPoSCancel, NodeContext* m_node)
108
120
  {
109
121
  int64_t nTimeStart = GetTimeMicros();
110
122
 
@@ -116,25 +128,67 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
116
128
  return nullptr;
117
129
  }
118
130
  CBlock* const pblock = &pblocktemplate->block; // pointer for convenience
131
+ pblock->nTime = GetAdjustedTime();
132
+
133
+ LOCK2(cs_main, m_mempool.cs);
134
+
135
+ CBlockIndex* pindexPrev = m_node->chainman->ActiveChain().Tip();
136
+ assert(pindexPrev != nullptr);
137
+ nHeight = pindexPrev->nHeight + 1;
138
+
139
+ // Create coinbase transaction.
140
+ CMutableTransaction coinbaseTx;
141
+ coinbaseTx.vin.resize(1);
142
+ coinbaseTx.vin[0].prevout.SetNull();
143
+ coinbaseTx.vout.resize(1);
144
+ coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn;
145
+
146
+ if (pwallet == nullptr) {
147
+ pblock->nBits = GetNextTargetRequired(pindexPrev, false, chainparams.GetConsensus());
148
+ coinbaseTx.vout[0].nValue = GetProofOfWorkReward(pblock->nBits, pblock->nTime);
149
+ }
119
150
 
120
151
  // Add dummy coinbase tx as first transaction
121
152
  pblock->vtx.emplace_back();
122
153
  pblocktemplate->vTxFees.push_back(-1); // updated at end
123
154
  pblocktemplate->vTxSigOpsCost.push_back(-1); // updated at end
124
155
 
125
- LOCK2(cs_main, m_mempool.cs);
126
- CBlockIndex* pindexPrev = m_chainstate.m_chain.Tip();
127
- assert(pindexPrev != nullptr);
128
- nHeight = pindexPrev->nHeight + 1;
156
+ // peercoin: if coinstake available add coinstake tx
157
+ static int64_t nLastCoinStakeSearchTime = GetAdjustedTime(); // only initialized at startup
158
+
159
+ if (pwallet) // attemp to find a coinstake
160
+ {
161
+ *pfPoSCancel = true;
162
+ pblock->nBits = GetNextTargetRequired(pindexPrev, true, chainparams.GetConsensus());
163
+ CMutableTransaction txCoinStake;
164
+ int64_t nSearchTime = txCoinStake.nTime; // search to current time
165
+ if (nSearchTime > nLastCoinStakeSearchTime)
166
+ {
167
+ if (pwallet->CreateCoinStake(*m_node->chainman, pwallet, pblock->nBits, nSearchTime-nLastCoinStakeSearchTime, txCoinStake))
168
+ {
169
+ if (txCoinStake.nTime >= std::max(pindexPrev->GetMedianTimePast()+1, pindexPrev->GetBlockTime() - (IsProtocolV09(pindexPrev->GetBlockTime()) ? MAX_FUTURE_BLOCK_TIME : MAX_FUTURE_BLOCK_TIME_PREV9)))
170
+ { // make sure coinstake would meet timestamp protocol
171
+ // as it would be the same as the block timestamp
172
+ coinbaseTx.vout[0].SetEmpty();
173
+ coinbaseTx.nTime = txCoinStake.nTime;
174
+ pblock->vtx.push_back(MakeTransactionRef(CTransaction(txCoinStake)));
175
+ *pfPoSCancel = false;
176
+ }
177
+ }
178
+ nLastCoinStakeSearchInterval = nSearchTime - nLastCoinStakeSearchTime;
179
+ nLastCoinStakeSearchTime = nSearchTime;
180
+ }
181
+ if (*pfPoSCancel)
182
+ return nullptr; // peercoin: there is no point to continue if we failed to create coinstake
183
+ pblock->nFlags = CBlockIndex::BLOCK_PROOF_OF_STAKE;
184
+ }
129
185
 
130
- pblock->nVersion = g_versionbitscache.ComputeBlockVersion(pindexPrev, chainparams.GetConsensus());
131
186
  // -regtest only: allow overriding block.nVersion with
132
187
  // -blockversion=N to test forking scenarios
133
188
  if (chainparams.MineBlocksOnDemand()) {
134
189
  pblock->nVersion = gArgs.GetIntArg("-blockversion", pblock->nVersion);
135
190
  }
136
191
 
137
- pblock->nTime = GetAdjustedTime();
138
192
  m_lock_time_cutoff = pindexPrev->GetMedianTimePast();
139
193
 
140
194
  // Decide whether to include witness transactions
@@ -146,40 +200,38 @@ std::unique_ptr<CBlockTemplate> BlockAssembler::CreateNewBlock(const CScript& sc
146
200
  // not activated.
147
201
  // TODO: replace this with a call to main to assess validity of a mempool
148
202
  // transaction (which in most cases can be a no-op).
149
- fIncludeWitness = DeploymentActiveAfter(pindexPrev, chainparams.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT);
203
+ fIncludeWitness = IsBTC16BIPsEnabled(pindexPrev->nTime);
150
204
 
151
205
  int nPackagesSelected = 0;
152
206
  int nDescendantsUpdated = 0;
153
- addPackageTxs(nPackagesSelected, nDescendantsUpdated);
207
+ addPackageTxs(nPackagesSelected, nDescendantsUpdated, pblock->nTime);
154
208
 
155
209
  int64_t nTime1 = GetTimeMicros();
156
210
 
157
211
  m_last_block_num_txs = nBlockTx;
158
212
  m_last_block_weight = nBlockWeight;
159
213
 
160
- // Create coinbase transaction.
161
- CMutableTransaction coinbaseTx;
162
- coinbaseTx.vin.resize(1);
163
- coinbaseTx.vin[0].prevout.SetNull();
164
- coinbaseTx.vout.resize(1);
165
- coinbaseTx.vout[0].scriptPubKey = scriptPubKeyIn;
166
- coinbaseTx.vout[0].nValue = nFees + GetBlockSubsidy(nHeight, chainparams.GetConsensus());
167
214
  coinbaseTx.vin[0].scriptSig = CScript() << nHeight << OP_0;
168
215
  pblock->vtx[0] = MakeTransactionRef(std::move(coinbaseTx));
169
- pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus());
216
+ if (fIncludeWitness)
217
+ pblocktemplate->vchCoinbaseCommitment = GenerateCoinbaseCommitment(*pblock, pindexPrev, chainparams.GetConsensus());
170
218
  pblocktemplate->vTxFees[0] = -nFees;
171
219
 
172
220
  LogPrintf("CreateNewBlock(): block weight: %u txs: %u fees: %ld sigops %d\n", GetBlockWeight(*pblock), nBlockTx, nFees, nBlockSigOpsCost);
173
221
 
174
222
  // Fill in header
175
223
  pblock->hashPrevBlock = pindexPrev->GetBlockHash();
176
- UpdateTime(pblock, chainparams.GetConsensus(), pindexPrev);
177
- pblock->nBits = GetNextWorkRequired(pindexPrev, pblock, chainparams.GetConsensus());
224
+ if (pblock->IsProofOfStake())
225
+ pblock->nTime = pblock->vtx[1]->nTime; //same as coinstake timestamp
226
+ pblock->nTime = std::max(pindexPrev->GetMedianTimePast()+1, pblock->GetMaxTransactionTime());
227
+ pblock->nTime = std::max(pblock->GetBlockTime(), pindexPrev->GetBlockTime() - (IsProtocolV09(pindexPrev->GetBlockTime()) ? MAX_FUTURE_BLOCK_TIME : MAX_FUTURE_BLOCK_TIME_PREV9));
228
+ if (pblock->IsProofOfWork())
229
+ UpdateTime(pblock);
178
230
  pblock->nNonce = 0;
179
231
  pblocktemplate->vTxSigOpsCost[0] = WITNESS_SCALE_FACTOR * GetLegacySigOpCount(*pblock->vtx[0]);
180
232
 
181
233
  BlockValidationState state;
182
- if (!TestBlockValidity(state, chainparams, m_chainstate, *pblock, pindexPrev, false, false)) {
234
+ if (pwallet && !TestBlockValidity(state, chainparams, m_chainstate, *pblock, pindexPrev, false, false)) {
183
235
  throw std::runtime_error(strprintf("%s: TestBlockValidity failed: %s", __func__, state.ToString()));
184
236
  }
185
237
  int64_t nTime2 = GetTimeMicros();
@@ -217,7 +269,7 @@ bool BlockAssembler::TestPackage(uint64_t packageSize, int64_t packageSigOpsCost
217
269
  // - transaction finality (locktime)
218
270
  // - premature witness (in case segwit transactions are added to mempool before
219
271
  // segwit activation)
220
- bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package) const
272
+ bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& package, uint32_t nTime) const
221
273
  {
222
274
  for (CTxMemPool::txiter it : package) {
223
275
  if (!IsFinalTx(it->GetTx(), nHeight, m_lock_time_cutoff)) {
@@ -225,6 +277,10 @@ bool BlockAssembler::TestPackageTransactions(const CTxMemPool::setEntries& packa
225
277
  }
226
278
  if (!fIncludeWitness && it->GetTx().HasWitness()) {
227
279
  return false;
280
+
281
+ // peercoin: timestamp limit
282
+ if (it->GetTx().nTime > GetAdjustedTime() || (nTime && it->GetTx().nTime > nTime))
283
+ return false;
228
284
  }
229
285
  }
230
286
  return true;
@@ -243,8 +299,8 @@ void BlockAssembler::AddToBlock(CTxMemPool::txiter iter)
243
299
 
244
300
  bool fPrintPriority = gArgs.GetBoolArg("-printpriority", DEFAULT_PRINTPRIORITY);
245
301
  if (fPrintPriority) {
246
- LogPrintf("fee rate %s txid %s\n",
247
- CFeeRate(iter->GetModifiedFee(), iter->GetTxSize()).ToString(),
302
+ LogPrintf("fee %d satoshi txid %s\n",
303
+ iter->GetModifiedFee(),
248
304
  iter->GetTx().GetHash().ToString());
249
305
  }
250
306
  }
@@ -317,7 +373,7 @@ void BlockAssembler::SortForBlock(const CTxMemPool::setEntries& package, std::ve
317
373
  // Each time through the loop, we compare the best transaction in
318
374
  // mapModifiedTxs with the next transaction in the mempool to decide what
319
375
  // transaction package to work on next.
320
- void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpdated)
376
+ void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpdated, uint32_t nTime)
321
377
  {
322
378
  AssertLockHeld(m_mempool.cs);
323
379
 
@@ -379,19 +435,12 @@ void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpda
379
435
  assert(!inBlock.count(iter));
380
436
 
381
437
  uint64_t packageSize = iter->GetSizeWithAncestors();
382
- CAmount packageFees = iter->GetModFeesWithAncestors();
383
438
  int64_t packageSigOpsCost = iter->GetSigOpCostWithAncestors();
384
439
  if (fUsingModified) {
385
440
  packageSize = modit->nSizeWithAncestors;
386
- packageFees = modit->nModFeesWithAncestors;
387
441
  packageSigOpsCost = modit->nSigOpCostWithAncestors;
388
442
  }
389
443
 
390
- if (packageFees < blockMinFeeRate.GetFee(packageSize)) {
391
- // Everything else we might consider has a lower fee rate
392
- return;
393
- }
394
-
395
444
  if (!TestPackage(packageSize, packageSigOpsCost)) {
396
445
  if (fUsingModified) {
397
446
  // Since we always look at the best entry in mapModifiedTx,
@@ -420,7 +469,7 @@ void BlockAssembler::addPackageTxs(int& nPackagesSelected, int& nDescendantsUpda
420
469
  ancestors.insert(iter);
421
470
 
422
471
  // Test if all tx's are Final
423
- if (!TestPackageTransactions(ancestors)) {
472
+ if (!TestPackageTransactions(ancestors,nTime)) {
424
473
  if (fUsingModified) {
425
474
  mapModifiedTx.get<ancestor_score>().erase(modit);
426
475
  failedTx.insert(iter);
@@ -465,4 +514,208 @@ void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned
465
514
  pblock->vtx[0] = MakeTransactionRef(std::move(txCoinbase));
466
515
  pblock->hashMerkleRoot = BlockMerkleRoot(*pblock);
467
516
  }
517
+
518
+
519
+ static bool ProcessBlockFound(const CBlock* pblock, const CChainParams& chainparams, NodeContext& m_node)
520
+ {
521
+ LogPrintf("%s\n", pblock->ToString());
522
+ LogPrintf("generated %s\n", FormatMoney(pblock->vtx[0]->vout[0].nValue));
523
+
524
+ // Found a solution
525
+ {
526
+ LOCK(cs_main);
527
+ if (pblock->hashPrevBlock != m_node.chainman->ActiveChain().Tip()->GetBlockHash())
528
+ return error("PeercoinMiner: generated block is stale");
529
+ }
530
+
531
+ // Process this block the same as if we had received it from another node
532
+ std::shared_ptr<const CBlock> shared_pblock = std::make_shared<const CBlock>(*pblock);
533
+ if (!m_node.chainman->ProcessNewBlock(Params(), shared_pblock, true, NULL))
534
+ return error("ProcessNewBlock, block not accepted");
535
+
536
+ return true;
537
+ }
538
+
539
+ void PoSMiner(std::shared_ptr<CWallet> pwallet, NodeContext& m_node)
540
+ {
541
+ CConnman* connman = m_node.connman.get();
542
+ LogPrintf("CPUMiner started for proof-of-stake\n");
543
+ util::ThreadRename("peercoin-stake-minter");
544
+
545
+ unsigned int nExtraNonce = 0;
546
+
547
+ OutputType output_type = pwallet->m_default_change_type ? *pwallet->m_default_change_type : pwallet->m_default_address_type;
548
+ ReserveDestination reservedest(pwallet.get(), output_type);
549
+ CTxDestination dest;
550
+ // Compute timeout for pos as sqrt(numUTXO)
551
+ unsigned int pos_timio;
552
+ {
553
+ LOCK2(pwallet->cs_wallet, cs_main);
554
+ bilingual_str dest_err;
555
+ if (!reservedest.GetReservedDestination(dest, true, dest_err))
556
+ throw std::runtime_error("Error: Keypool ran out, please call keypoolrefill first.");
557
+
558
+ std::vector<COutput> vCoins;
559
+ CCoinControl coincontrol;
560
+ AvailableCoins(*pwallet, vCoins, &coincontrol);
561
+ pos_timio = 500 + 30 * sqrt(vCoins.size());
562
+ LogPrintf("Set proof-of-stake timeout: %ums for %u UTXOs\n", pos_timio, vCoins.size());
563
+ }
564
+
565
+ std::string strMintMessage = _("Info: Minting suspended due to locked wallet.").translated;
566
+ std::string strMintSyncMessage = _("Info: Minting suspended while synchronizing wallet.").translated;
567
+ std::string strMintDisabledMessage = _("Info: Minting disabled by 'nominting' option.").translated;
568
+ std::string strMintBlockMessage = _("Info: Minting suspended due to block creation failure.").translated;
569
+ std::string strMintEmpty = "";
570
+ if (!gArgs.GetBoolArg("-minting", true) || !gArgs.GetBoolArg("-staking", true))
571
+ {
572
+ strMintWarning = strMintDisabledMessage;
573
+ LogPrintf("proof-of-stake minter disabled\n");
574
+ return;
575
+ }
576
+
577
+ try {
578
+ bool fNeedToClear = false;
579
+ while (true) {
580
+ while (pwallet->IsLocked()) {
581
+ if (strMintWarning != strMintMessage) {
582
+ strMintWarning = strMintMessage;
583
+ uiInterface.NotifyAlertChanged(uint256(), CT_UPDATED);
584
+ }
585
+ fNeedToClear = true;
586
+ if (!connman->interruptNet.sleep_for(std::chrono::seconds(3)))
587
+ return;
588
+ }
589
+
590
+ if (Params().MiningRequiresPeers()) {
591
+ // Busy-wait for the network to come online so we don't waste time mining
592
+ // on an obsolete chain. In regtest mode we expect to fly solo.
593
+ while(connman == nullptr || connman->GetNodeCount(ConnectionDirection::Both) == 0 || m_node.chainman->ActiveChainstate().IsInitialBlockDownload()) {
594
+ while(connman == nullptr) {UninterruptibleSleep(1s);}
595
+ if (!connman->interruptNet.sleep_for(std::chrono::seconds(10)))
596
+ return;
597
+ }
598
+ }
599
+
600
+ while (GuessVerificationProgress(Params().TxData(), m_node.chainman->ActiveChain().Tip()) < 0.996)
601
+ {
602
+ LogPrintf("Minter thread sleeps while sync at %f\n", GuessVerificationProgress(Params().TxData(), m_node.chainman->ActiveChain().Tip()));
603
+ if (strMintWarning != strMintSyncMessage) {
604
+ strMintWarning = strMintSyncMessage;
605
+ uiInterface.NotifyAlertChanged(uint256(), CT_UPDATED);
606
+ }
607
+ fNeedToClear = true;
608
+ if (!connman->interruptNet.sleep_for(std::chrono::seconds(10)))
609
+ return;
610
+ }
611
+ if (fNeedToClear) {
612
+ strMintWarning = strMintEmpty;
613
+ uiInterface.NotifyAlertChanged(uint256(), CT_UPDATED);
614
+ fNeedToClear = false;
615
+ }
616
+
617
+ //
618
+ // Create new block
619
+ //
620
+ CBlockIndex* pindexPrev = m_node.chainman->ActiveChain().Tip();
621
+ bool fPoSCancel = false;
622
+ CScript scriptPubKey = GetScriptForDestination(dest);
623
+ CBlock *pblock;
624
+ std::unique_ptr<CBlockTemplate> pblocktemplate;
625
+
626
+ {
627
+ LOCK2(pwallet->cs_wallet, cs_main);
628
+ try {
629
+ pblocktemplate = BlockAssembler(m_node.chainman->ActiveChainstate(), *m_node.mempool, Params()).CreateNewBlock(scriptPubKey, pwallet.get(), &fPoSCancel, &m_node);
630
+ }
631
+ catch (const std::runtime_error &e)
632
+ {
633
+ LogPrintf("PeercoinMiner runtime error: %s\n", e.what());
634
+ continue;
635
+ }
636
+ }
637
+
638
+ if (!pblocktemplate.get())
639
+ {
640
+ if (fPoSCancel == true)
641
+ {
642
+ if (!connman->interruptNet.sleep_for(std::chrono::milliseconds(pos_timio)))
643
+ return;
644
+ continue;
645
+ }
646
+ strMintWarning = strMintBlockMessage;
647
+ uiInterface.NotifyAlertChanged(uint256(), CT_UPDATED);
648
+ LogPrintf("Error in PeercoinMiner: Keypool ran out, please call keypoolrefill before restarting the mining thread\n");
649
+ if (!connman->interruptNet.sleep_for(std::chrono::seconds(10)))
650
+ return;
651
+
652
+ return;
653
+ }
654
+ pblock = &pblocktemplate->block;
655
+ IncrementExtraNonce(pblock, pindexPrev, nExtraNonce);
656
+
657
+ // peercoin: if proof-of-stake block found then process block
658
+ if (pblock->IsProofOfStake())
659
+ {
660
+ {
661
+ LOCK2(pwallet->cs_wallet, cs_main);
662
+ if (!SignBlock(*pblock, *pwallet))
663
+ {
664
+ LogPrintf("PoSMiner(): failed to sign PoS block");
665
+ continue;
666
+ }
667
+ }
668
+ LogPrintf("CPUMiner : proof-of-stake block found %s\n", pblock->GetHash().ToString());
669
+ try {
670
+ ProcessBlockFound(pblock, Params(), m_node);
671
+ }
672
+ catch (const std::runtime_error &e)
673
+ {
674
+ LogPrintf("PeercoinMiner runtime error: %s\n", e.what());
675
+ continue;
676
+ }
677
+ reservedest.KeepDestination();
678
+ // Rest for ~3 minutes after successful block to preserve close quick
679
+ if (!connman->interruptNet.sleep_for(std::chrono::seconds(60 + GetRand(4))))
680
+ return;
681
+ }
682
+ if (!connman->interruptNet.sleep_for(std::chrono::milliseconds(pos_timio)))
683
+ return;
684
+
685
+ continue;
686
+ }
687
+ }
688
+ catch (::boost::thread_interrupted)
689
+ {
690
+ LogPrintf("PeercoinMiner terminated\n");
691
+ return;
692
+ }
693
+ catch (const std::runtime_error &e)
694
+ {
695
+ LogPrintf("PeercoinMiner runtime error: %s\n", e.what());
696
+ return;
697
+ }
698
+ }
699
+
700
+ // peercoin: stake minter thread
701
+ void static ThreadStakeMinter(std::shared_ptr<CWallet> pwallet, NodeContext& m_node)
702
+ {
703
+ LogPrintf("ThreadStakeMinter started\n");
704
+ try
705
+ {
706
+ PoSMiner(pwallet, m_node);
707
+ }
708
+ catch (std::exception& e) {
709
+ PrintExceptionContinue(&e, "ThreadStakeMinter()");
710
+ } catch (...) {
711
+ PrintExceptionContinue(NULL, "ThreadStakeMinter()");
712
+ }
713
+ LogPrintf("ThreadStakeMinter exiting\n");
714
+ }
715
+
716
+ // peercoin: stake minter
717
+ void MintStake(std::shared_ptr<CWallet> pwallet, NodeContext& m_node)
718
+ {
719
+ m_minter_thread = std::thread([&] { util::TraceThread("minter", [&] { ThreadStakeMinter(pwallet, m_node); }); });
720
+ }
468
721
  } // namespace node
src/node/miner.h CHANGED
@@ -8,15 +8,18 @@
8
8
 
9
9
  #include <primitives/block.h>
10
10
  #include <txmempool.h>
11
-
11
+ #include <node/context.h>
12
12
  #include <memory>
13
13
  #include <optional>
14
14
  #include <stdint.h>
15
+ #include <wallet/wallet.h>
15
16
 
16
17
  #include <boost/multi_index/ordered_index.hpp>
17
18
  #include <boost/multi_index_container.hpp>
18
19
 
20
+ extern int64_t nLastCoinStakeSearchInterval;
19
21
  class ChainstateManager;
22
+
20
23
  class CBlockIndex;
21
24
  class CChainParams;
22
25
  class CScript;
@@ -134,7 +137,6 @@ private:
134
137
  // Configuration parameters for the block size
135
138
  bool fIncludeWitness;
136
139
  unsigned int nBlockMaxWeight;
137
- CFeeRate blockMinFeeRate;
138
140
 
139
141
  // Information on the current status of the block
140
142
  uint64_t nBlockWeight;
@@ -155,14 +157,14 @@ public:
155
157
  struct Options {
156
158
  Options();
157
159
  size_t nBlockMaxWeight;
158
- CFeeRate blockMinFeeRate;
159
160
  };
160
161
 
161
162
  explicit BlockAssembler(CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params);
162
163
  explicit BlockAssembler(CChainState& chainstate, const CTxMemPool& mempool, const CChainParams& params, const Options& options);
163
164
 
164
165
  /** Construct a new block template with coinbase to scriptPubKeyIn */
165
- std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn);
166
+ std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn, CWallet* pwallet=nullptr, bool* pfPoSCancel=nullptr, NodeContext* m_node=nullptr);
167
+ //std::unique_ptr<CBlockTemplate> CreateNewBlock(const CScript& scriptPubKeyIn);
166
168
 
167
169
  inline static std::optional<int64_t> m_last_block_num_txs{};
168
170
  inline static std::optional<int64_t> m_last_block_weight{};
@@ -178,7 +180,7 @@ private:
178
180
  /** Add transactions based on feerate including unconfirmed ancestors
179
181
  * Increments nPackagesSelected / nDescendantsUpdated with corresponding
180
182
  * statistics from the package selection (for logging statistics). */
181
- void addPackageTxs(int& nPackagesSelected, int& nDescendantsUpdated) EXCLUSIVE_LOCKS_REQUIRED(m_mempool.cs);
183
+ void addPackageTxs(int& nPackagesSelected, int& nDescendantsUpdated, uint32_t nTime) EXCLUSIVE_LOCKS_REQUIRED(m_mempool.cs);
182
184
 
183
185
  // helper functions for addPackageTxs()
184
186
  /** Remove confirmed (inBlock) entries from given set */
@@ -189,7 +191,7 @@ private:
189
191
  * locktime, premature-witness, serialized size (if necessary)
190
192
  * These checks should always succeed, and they're here
191
193
  * only as an extra check in case of suboptimal node configuration */
192
- bool TestPackageTransactions(const CTxMemPool::setEntries& package) const;
194
+ bool TestPackageTransactions(const CTxMemPool::setEntries& package, uint32_t nTime) const;
193
195
  /** Return true if given transaction from mapTx has already been evaluated,
194
196
  * or if the transaction's cached data in mapTx is incorrect. */
195
197
  bool SkipMapTxEntry(CTxMemPool::txiter it, indexed_modified_transaction_set& mapModifiedTx, CTxMemPool::setEntries& failedTx) EXCLUSIVE_LOCKS_REQUIRED(m_mempool.cs);
@@ -203,7 +205,13 @@ private:
203
205
 
204
206
  /** Modify the extranonce in a block */
205
207
  void IncrementExtraNonce(CBlock* pblock, const CBlockIndex* pindexPrev, unsigned int& nExtraNonce);
206
- int64_t UpdateTime(CBlockHeader* pblock, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev);
208
+ int64_t UpdateTime(CBlockHeader* pblock);
209
+
210
+ namespace boost {
211
+ class thread_group;
212
+ } // namespace boost
213
+
214
+ void MintStake(std::shared_ptr<CWallet> pwallet, NodeContext& m_node);
207
215
 
208
216
  /** Update an old GenerateCoinbaseCommitment from CreateNewBlock after the block txs have changed */
209
217
  void RegenerateCommitments(CBlock& block, ChainstateManager& chainman);
src/node/psbt.cpp CHANGED
@@ -5,9 +5,11 @@
5
5
  #include <coins.h>
6
6
  #include <consensus/amount.h>
7
7
  #include <consensus/tx_verify.h>
8
+ #include <kernel.h>
8
9
  #include <node/psbt.h>
9
10
  #include <policy/policy.h>
10
11
  #include <policy/settings.h>
12
+ #include <timedata.h>
11
13
  #include <tinyformat.h>
12
14
 
13
15
  #include <numeric>
@@ -131,7 +133,7 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
131
133
  mtx.vin[i].scriptSig = input.final_script_sig;
132
134
  mtx.vin[i].scriptWitness = input.final_script_witness;
133
135
  newcoin.nHeight = 1;
134
- view.AddCoin(psbtx.tx->vin[i].prevout, std::move(newcoin), true);
136
+ view.AddCoin(psbtx.tx->vin[i].prevout, std::move(newcoin), true, true);
135
137
  }
136
138
  }
137
139
 
@@ -139,9 +141,6 @@ PSBTAnalysis AnalyzePSBT(PartiallySignedTransaction psbtx)
139
141
  CTransaction ctx = CTransaction(mtx);
140
142
  size_t size = GetVirtualTransactionSize(ctx, GetTransactionSigOpCost(ctx, view, STANDARD_SCRIPT_VERIFY_FLAGS));
141
143
  result.estimated_vsize = size;
142
- // Estimate fee rate
143
- CFeeRate feerate(fee, size);
144
- result.estimated_feerate = feerate;
145
144
  }
146
145
 
147
146
  }
src/node/psbt.h CHANGED
@@ -29,7 +29,6 @@ struct PSBTInputAnalysis {
29
29
  */
30
30
  struct PSBTAnalysis {
31
31
  std::optional<size_t> estimated_vsize; //!< Estimated weight of the transaction
32
- std::optional<CFeeRate> estimated_feerate; //!< Estimated feerate (fee / weight) of the transaction
33
32
  std::optional<CAmount> fee; //!< Amount of fee being paid by the transaction
34
33
  std::vector<PSBTInputAnalysis> inputs; //!< More information about the individual inputs of the transaction
35
34
  PSBTRole next; //!< Which of the BIP 174 roles needs to handle the transaction next
@@ -38,7 +37,6 @@ struct PSBTAnalysis {
38
37
  void SetInvalid(std::string err_msg)
39
38
  {
40
39
  estimated_vsize = std::nullopt;
41
- estimated_feerate = std::nullopt;
42
40
  fee = std::nullopt;
43
41
  inputs.clear();
44
42
  next = PSBTRole::CREATOR;
src/node/transaction.cpp CHANGED
@@ -30,7 +30,7 @@ static TransactionError HandleATMPError(const TxValidationState& state, std::str
30
30
  }
31
31
  }
32
32
 
33
- TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback)
33
+ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef tx, std::string& err_string, bool relay, bool wait_callback)
34
34
  {
35
35
  // BroadcastTransaction can be called by either sendrawtransaction RPC or the wallet.
36
36
  // chainman, mempool and peerman are initialized before the RPC server and wallet are started
@@ -68,16 +68,6 @@ TransactionError BroadcastTransaction(NodeContext& node, const CTransactionRef t
68
68
  wtxid = mempool_tx->GetWitnessHash();
69
69
  } else {
70
70
  // Transaction is not already in the mempool.
71
- if (max_tx_fee > 0) {
72
- // First, call ATMP with test_accept and check the fee. If ATMP
73
- // fails here, return error immediately.
74
- const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/ true);
75
- if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
76
- return HandleATMPError(result.m_state, err_string);
77
- } else if (result.m_base_fees.value() > max_tx_fee) {
78
- return TransactionError::MAX_FEE_EXCEEDED;
79
- }
80
- }
81
71
  // Try to submit the transaction to the mempool.
82
72
  const MempoolAcceptResult result = node.chainman->ProcessTransaction(tx, /*test_accept=*/ false);
83
73
  if (result.m_result_type != MempoolAcceptResult::ResultType::VALID) {
src/node/transaction.h CHANGED
@@ -6,7 +6,6 @@
6
6
  #define BITCOIN_NODE_TRANSACTION_H
7
7
 
8
8
  #include <attributes.h>
9
- #include <policy/feerate.h>
10
9
  #include <primitives/transaction.h>
11
10
  #include <util/error.h>
12
11
 
@@ -19,13 +18,6 @@ struct Params;
19
18
  namespace node {
20
19
  struct NodeContext;
21
20
 
22
- /** Maximum fee rate for sendrawtransaction and testmempoolaccept RPC calls.
23
- * Also used by the GUI when broadcasting a completed PSBT.
24
- * By default, a transaction with a fee rate higher than this will be rejected
25
- * by these RPCs and the GUI. This can be overridden with the maxfeerate argument.
26
- */
27
- static const CFeeRate DEFAULT_MAX_RAW_TX_FEE_RATE{COIN / 10};
28
-
29
21
  /**
30
22
  * Submit a transaction to the mempool and (optionally) relay it to all P2P peers.
31
23
  *
@@ -38,12 +30,11 @@ static const CFeeRate DEFAULT_MAX_RAW_TX_FEE_RATE{COIN / 10};
38
30
  * @param[in] node reference to node context
39
31
  * @param[in] tx the transaction to broadcast
40
32
  * @param[out] err_string reference to std::string to fill with error string if available
41
- * @param[in] max_tx_fee reject txs with fees higher than this (if 0, accept any fee)
42
33
  * @param[in] relay flag if both mempool insertion and p2p relay are requested
43
34
  * @param[in] wait_callback wait until callbacks have been processed to avoid stale result due to a sequentially RPC.
44
35
  * return error
45
36
  */
46
- [[nodiscard]] TransactionError BroadcastTransaction(NodeContext& node, CTransactionRef tx, std::string& err_string, const CAmount& max_tx_fee, bool relay, bool wait_callback);
37
+ [[nodiscard]] TransactionError BroadcastTransaction(NodeContext& node, CTransactionRef tx, std::string& err_string, bool relay, bool wait_callback);
47
38
 
48
39
  /**
49
40
  * Return transaction with a given hash.
src/node/ui_interface.cpp CHANGED
@@ -50,7 +50,7 @@ void CClientUIInterface::InitMessage(const std::string& message) { return g_ui_s
50
50
  void CClientUIInterface::InitWallet() { return g_ui_signals.InitWallet(); }
51
51
  void CClientUIInterface::NotifyNumConnectionsChanged(int newNumConnections) { return g_ui_signals.NotifyNumConnectionsChanged(newNumConnections); }
52
52
  void CClientUIInterface::NotifyNetworkActiveChanged(bool networkActive) { return g_ui_signals.NotifyNetworkActiveChanged(networkActive); }
53
- void CClientUIInterface::NotifyAlertChanged() { return g_ui_signals.NotifyAlertChanged(); }
53
+ void CClientUIInterface::NotifyAlertChanged(const uint256 &hash, ChangeType status) { return g_ui_signals.NotifyAlertChanged(hash, status); }
54
54
  void CClientUIInterface::ShowProgress(const std::string& title, int nProgress, bool resume_possible) { return g_ui_signals.ShowProgress(title, nProgress, resume_possible); }
55
55
  void CClientUIInterface::NotifyBlockTip(SynchronizationState s, const CBlockIndex* i) { return g_ui_signals.NotifyBlockTip(s, i); }
56
56
  void CClientUIInterface::NotifyHeaderTip(SynchronizationState s, const CBlockIndex* i) { return g_ui_signals.NotifyHeaderTip(s, i); }
src/node/ui_interface.h CHANGED
@@ -9,8 +9,10 @@
9
9
  #include <functional>
10
10
  #include <memory>
11
11
  #include <string>
12
+ #include <util/ui_change_type.h>
12
13
 
13
14
  class CBlockIndex;
15
+ class uint256;
14
16
  enum class SynchronizationState;
15
17
  struct bilingual_str;
16
18
 
@@ -93,7 +95,7 @@ public:
93
95
  /**
94
96
  * Status bar alerts changed.
95
97
  */
96
- ADD_SIGNALS_DECL_WRAPPER(NotifyAlertChanged, void, );
98
+ ADD_SIGNALS_DECL_WRAPPER(NotifyAlertChanged, void, const uint256 &hash, ChangeType status);
97
99
 
98
100
  /**
99
101
  * Show progress e.g. for verifychain.
src/policy/feerate.cpp DELETED
@@ -1,45 +0,0 @@
1
- // Copyright (c) 2009-2010 Satoshi Nakamoto
2
- // Copyright (c) 2009-2021 The Bitcoin Core developers
3
- // Distributed under the MIT software license, see the accompanying
4
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
-
6
- #include <policy/feerate.h>
7
-
8
- #include <tinyformat.h>
9
-
10
- #include <cmath>
11
-
12
- CFeeRate::CFeeRate(const CAmount& nFeePaid, uint32_t num_bytes)
13
- {
14
- const int64_t nSize{num_bytes};
15
-
16
- if (nSize > 0) {
17
- nSatoshisPerK = nFeePaid * 1000 / nSize;
18
- } else {
19
- nSatoshisPerK = 0;
20
- }
21
- }
22
-
23
- CAmount CFeeRate::GetFee(uint32_t num_bytes) const
24
- {
25
- const int64_t nSize{num_bytes};
26
-
27
- // Be explicit that we're converting from a double to int64_t (CAmount) here.
28
- // We've previously had issues with the silent double->int64_t conversion.
29
- CAmount nFee{static_cast<CAmount>(std::ceil(nSatoshisPerK * nSize / 1000.0))};
30
-
31
- if (nFee == 0 && nSize != 0) {
32
- if (nSatoshisPerK > 0) nFee = CAmount(1);
33
- if (nSatoshisPerK < 0) nFee = CAmount(-1);
34
- }
35
-
36
- return nFee;
37
- }
38
-
39
- std::string CFeeRate::ToString(const FeeEstimateMode& fee_estimate_mode) const
40
- {
41
- switch (fee_estimate_mode) {
42
- case FeeEstimateMode::SAT_VB: return strprintf("%d.%03d %s/vB", nSatoshisPerK / 1000, nSatoshisPerK % 1000, CURRENCY_ATOM);
43
- default: return strprintf("%d.%08d %s/kvB", nSatoshisPerK / COIN, nSatoshisPerK % COIN, CURRENCY_UNIT);
44
- }
45
- }
src/policy/feerate.h DELETED
@@ -1,75 +0,0 @@
1
- // Copyright (c) 2009-2010 Satoshi Nakamoto
2
- // Copyright (c) 2009-2021 The Bitcoin Core developers
3
- // Distributed under the MIT software license, see the accompanying
4
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
-
6
- #ifndef BITCOIN_POLICY_FEERATE_H
7
- #define BITCOIN_POLICY_FEERATE_H
8
-
9
- #include <consensus/amount.h>
10
- #include <serialize.h>
11
-
12
- #include <string>
13
-
14
- const std::string CURRENCY_UNIT = "BTC"; // One formatted unit
15
- const std::string CURRENCY_ATOM = "sat"; // One indivisible minimum value unit
16
-
17
- /* Used to determine type of fee estimation requested */
18
- enum class FeeEstimateMode {
19
- UNSET, //!< Use default settings based on other criteria
20
- ECONOMICAL, //!< Force estimateSmartFee to use non-conservative estimates
21
- CONSERVATIVE, //!< Force estimateSmartFee to use conservative estimates
22
- BTC_KVB, //!< Use BTC/kvB fee rate unit
23
- SAT_VB, //!< Use sat/vB fee rate unit
24
- };
25
-
26
- /**
27
- * Fee rate in satoshis per kilovirtualbyte: CAmount / kvB
28
- */
29
- class CFeeRate
30
- {
31
- private:
32
- /** Fee rate in sat/kvB (satoshis per 1000 virtualbytes) */
33
- CAmount nSatoshisPerK;
34
-
35
- public:
36
- /** Fee rate of 0 satoshis per kvB */
37
- CFeeRate() : nSatoshisPerK(0) { }
38
- template<typename I>
39
- explicit CFeeRate(const I _nSatoshisPerK): nSatoshisPerK(_nSatoshisPerK) {
40
- // We've previously had bugs creep in from silent double->int conversion...
41
- static_assert(std::is_integral<I>::value, "CFeeRate should be used without floats");
42
- }
43
-
44
- /**
45
- * Construct a fee rate from a fee in satoshis and a vsize in vB.
46
- *
47
- * param@[in] nFeePaid The fee paid by a transaction, in satoshis
48
- * param@[in] num_bytes The vsize of a transaction, in vbytes
49
- */
50
- CFeeRate(const CAmount& nFeePaid, uint32_t num_bytes);
51
-
52
- /**
53
- * Return the fee in satoshis for the given vsize in vbytes.
54
- * If the calculated fee would have fractional satoshis, then the
55
- * returned fee will always be rounded up to the nearest satoshi.
56
- */
57
- CAmount GetFee(uint32_t num_bytes) const;
58
-
59
- /**
60
- * Return the fee in satoshis for a vsize of 1000 vbytes
61
- */
62
- CAmount GetFeePerK() const { return GetFee(1000); }
63
- friend bool operator<(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK < b.nSatoshisPerK; }
64
- friend bool operator>(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK > b.nSatoshisPerK; }
65
- friend bool operator==(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK == b.nSatoshisPerK; }
66
- friend bool operator<=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK <= b.nSatoshisPerK; }
67
- friend bool operator>=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK >= b.nSatoshisPerK; }
68
- friend bool operator!=(const CFeeRate& a, const CFeeRate& b) { return a.nSatoshisPerK != b.nSatoshisPerK; }
69
- CFeeRate& operator+=(const CFeeRate& a) { nSatoshisPerK += a.nSatoshisPerK; return *this; }
70
- std::string ToString(const FeeEstimateMode& fee_estimate_mode = FeeEstimateMode::BTC_KVB) const;
71
-
72
- SERIALIZE_METHODS(CFeeRate, obj) { READWRITE(obj.nSatoshisPerK); }
73
- };
74
-
75
- #endif // BITCOIN_POLICY_FEERATE_H
src/policy/fees.cpp DELETED
@@ -1,1017 +0,0 @@
1
- // Copyright (c) 2009-2010 Satoshi Nakamoto
2
- // Copyright (c) 2009-2021 The Bitcoin Core developers
3
- // Distributed under the MIT software license, see the accompanying
4
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
-
6
- #include <policy/fees.h>
7
-
8
- #include <clientversion.h>
9
- #include <fs.h>
10
- #include <logging.h>
11
- #include <streams.h>
12
- #include <txmempool.h>
13
- #include <util/serfloat.h>
14
- #include <util/system.h>
15
-
16
- static const char* FEE_ESTIMATES_FILENAME = "fee_estimates.dat";
17
-
18
- static constexpr double INF_FEERATE = 1e99;
19
-
20
- std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon)
21
- {
22
- switch (horizon) {
23
- case FeeEstimateHorizon::SHORT_HALFLIFE: return "short";
24
- case FeeEstimateHorizon::MED_HALFLIFE: return "medium";
25
- case FeeEstimateHorizon::LONG_HALFLIFE: return "long";
26
- } // no default case, so the compiler can warn about missing cases
27
- assert(false);
28
- }
29
-
30
- namespace {
31
-
32
- struct EncodedDoubleFormatter
33
- {
34
- template<typename Stream> void Ser(Stream &s, double v)
35
- {
36
- s << EncodeDouble(v);
37
- }
38
-
39
- template<typename Stream> void Unser(Stream& s, double& v)
40
- {
41
- uint64_t encoded;
42
- s >> encoded;
43
- v = DecodeDouble(encoded);
44
- }
45
- };
46
-
47
- } // namespace
48
-
49
- /**
50
- * We will instantiate an instance of this class to track transactions that were
51
- * included in a block. We will lump transactions into a bucket according to their
52
- * approximate feerate and then track how long it took for those txs to be included in a block
53
- *
54
- * The tracking of unconfirmed (mempool) transactions is completely independent of the
55
- * historical tracking of transactions that have been confirmed in a block.
56
- */
57
- class TxConfirmStats
58
- {
59
- private:
60
- //Define the buckets we will group transactions into
61
- const std::vector<double>& buckets; // The upper-bound of the range for the bucket (inclusive)
62
- const std::map<double, unsigned int>& bucketMap; // Map of bucket upper-bound to index into all vectors by bucket
63
-
64
- // For each bucket X:
65
- // Count the total # of txs in each bucket
66
- // Track the historical moving average of this total over blocks
67
- std::vector<double> txCtAvg;
68
-
69
- // Count the total # of txs confirmed within Y blocks in each bucket
70
- // Track the historical moving average of these totals over blocks
71
- std::vector<std::vector<double>> confAvg; // confAvg[Y][X]
72
-
73
- // Track moving avg of txs which have been evicted from the mempool
74
- // after failing to be confirmed within Y blocks
75
- std::vector<std::vector<double>> failAvg; // failAvg[Y][X]
76
-
77
- // Sum the total feerate of all tx's in each bucket
78
- // Track the historical moving average of this total over blocks
79
- std::vector<double> m_feerate_avg;
80
-
81
- // Combine the conf counts with tx counts to calculate the confirmation % for each Y,X
82
- // Combine the total value with the tx counts to calculate the avg feerate per bucket
83
-
84
- double decay;
85
-
86
- // Resolution (# of blocks) with which confirmations are tracked
87
- unsigned int scale;
88
-
89
- // Mempool counts of outstanding transactions
90
- // For each bucket X, track the number of transactions in the mempool
91
- // that are unconfirmed for each possible confirmation value Y
92
- std::vector<std::vector<int> > unconfTxs; //unconfTxs[Y][X]
93
- // transactions still unconfirmed after GetMaxConfirms for each bucket
94
- std::vector<int> oldUnconfTxs;
95
-
96
- void resizeInMemoryCounters(size_t newbuckets);
97
-
98
- public:
99
- /**
100
- * Create new TxConfirmStats. This is called by BlockPolicyEstimator's
101
- * constructor with default values.
102
- * @param defaultBuckets contains the upper limits for the bucket boundaries
103
- * @param maxPeriods max number of periods to track
104
- * @param decay how much to decay the historical moving average per block
105
- */
106
- TxConfirmStats(const std::vector<double>& defaultBuckets, const std::map<double, unsigned int>& defaultBucketMap,
107
- unsigned int maxPeriods, double decay, unsigned int scale);
108
-
109
- /** Roll the circular buffer for unconfirmed txs*/
110
- void ClearCurrent(unsigned int nBlockHeight);
111
-
112
- /**
113
- * Record a new transaction data point in the current block stats
114
- * @param blocksToConfirm the number of blocks it took this transaction to confirm
115
- * @param val the feerate of the transaction
116
- * @warning blocksToConfirm is 1-based and has to be >= 1
117
- */
118
- void Record(int blocksToConfirm, double val);
119
-
120
- /** Record a new transaction entering the mempool*/
121
- unsigned int NewTx(unsigned int nBlockHeight, double val);
122
-
123
- /** Remove a transaction from mempool tracking stats*/
124
- void removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight,
125
- unsigned int bucketIndex, bool inBlock);
126
-
127
- /** Update our estimates by decaying our historical moving average and updating
128
- with the data gathered from the current block */
129
- void UpdateMovingAverages();
130
-
131
- /**
132
- * Calculate a feerate estimate. Find the lowest value bucket (or range of buckets
133
- * to make sure we have enough data points) whose transactions still have sufficient likelihood
134
- * of being confirmed within the target number of confirmations
135
- * @param confTarget target number of confirmations
136
- * @param sufficientTxVal required average number of transactions per block in a bucket range
137
- * @param minSuccess the success probability we require
138
- * @param nBlockHeight the current block height
139
- */
140
- double EstimateMedianVal(int confTarget, double sufficientTxVal,
141
- double minSuccess, unsigned int nBlockHeight,
142
- EstimationResult *result = nullptr) const;
143
-
144
- /** Return the max number of confirms we're tracking */
145
- unsigned int GetMaxConfirms() const { return scale * confAvg.size(); }
146
-
147
- /** Write state of estimation data to a file*/
148
- void Write(CAutoFile& fileout) const;
149
-
150
- /**
151
- * Read saved state of estimation data from a file and replace all internal data structures and
152
- * variables with this state.
153
- */
154
- void Read(CAutoFile& filein, int nFileVersion, size_t numBuckets);
155
- };
156
-
157
-
158
- TxConfirmStats::TxConfirmStats(const std::vector<double>& defaultBuckets,
159
- const std::map<double, unsigned int>& defaultBucketMap,
160
- unsigned int maxPeriods, double _decay, unsigned int _scale)
161
- : buckets(defaultBuckets), bucketMap(defaultBucketMap), decay(_decay), scale(_scale)
162
- {
163
- assert(_scale != 0 && "_scale must be non-zero");
164
- confAvg.resize(maxPeriods);
165
- failAvg.resize(maxPeriods);
166
- for (unsigned int i = 0; i < maxPeriods; i++) {
167
- confAvg[i].resize(buckets.size());
168
- failAvg[i].resize(buckets.size());
169
- }
170
-
171
- txCtAvg.resize(buckets.size());
172
- m_feerate_avg.resize(buckets.size());
173
-
174
- resizeInMemoryCounters(buckets.size());
175
- }
176
-
177
- void TxConfirmStats::resizeInMemoryCounters(size_t newbuckets) {
178
- // newbuckets must be passed in because the buckets referred to during Read have not been updated yet.
179
- unconfTxs.resize(GetMaxConfirms());
180
- for (unsigned int i = 0; i < unconfTxs.size(); i++) {
181
- unconfTxs[i].resize(newbuckets);
182
- }
183
- oldUnconfTxs.resize(newbuckets);
184
- }
185
-
186
- // Roll the unconfirmed txs circular buffer
187
- void TxConfirmStats::ClearCurrent(unsigned int nBlockHeight)
188
- {
189
- for (unsigned int j = 0; j < buckets.size(); j++) {
190
- oldUnconfTxs[j] += unconfTxs[nBlockHeight % unconfTxs.size()][j];
191
- unconfTxs[nBlockHeight%unconfTxs.size()][j] = 0;
192
- }
193
- }
194
-
195
-
196
- void TxConfirmStats::Record(int blocksToConfirm, double feerate)
197
- {
198
- // blocksToConfirm is 1-based
199
- if (blocksToConfirm < 1)
200
- return;
201
- int periodsToConfirm = (blocksToConfirm + scale - 1) / scale;
202
- unsigned int bucketindex = bucketMap.lower_bound(feerate)->second;
203
- for (size_t i = periodsToConfirm; i <= confAvg.size(); i++) {
204
- confAvg[i - 1][bucketindex]++;
205
- }
206
- txCtAvg[bucketindex]++;
207
- m_feerate_avg[bucketindex] += feerate;
208
- }
209
-
210
- void TxConfirmStats::UpdateMovingAverages()
211
- {
212
- assert(confAvg.size() == failAvg.size());
213
- for (unsigned int j = 0; j < buckets.size(); j++) {
214
- for (unsigned int i = 0; i < confAvg.size(); i++) {
215
- confAvg[i][j] *= decay;
216
- failAvg[i][j] *= decay;
217
- }
218
- m_feerate_avg[j] *= decay;
219
- txCtAvg[j] *= decay;
220
- }
221
- }
222
-
223
- // returns -1 on error conditions
224
- double TxConfirmStats::EstimateMedianVal(int confTarget, double sufficientTxVal,
225
- double successBreakPoint, unsigned int nBlockHeight,
226
- EstimationResult *result) const
227
- {
228
- // Counters for a bucket (or range of buckets)
229
- double nConf = 0; // Number of tx's confirmed within the confTarget
230
- double totalNum = 0; // Total number of tx's that were ever confirmed
231
- int extraNum = 0; // Number of tx's still in mempool for confTarget or longer
232
- double failNum = 0; // Number of tx's that were never confirmed but removed from the mempool after confTarget
233
- const int periodTarget = (confTarget + scale - 1) / scale;
234
- const int maxbucketindex = buckets.size() - 1;
235
-
236
- // We'll combine buckets until we have enough samples.
237
- // The near and far variables will define the range we've combined
238
- // The best variables are the last range we saw which still had a high
239
- // enough confirmation rate to count as success.
240
- // The cur variables are the current range we're counting.
241
- unsigned int curNearBucket = maxbucketindex;
242
- unsigned int bestNearBucket = maxbucketindex;
243
- unsigned int curFarBucket = maxbucketindex;
244
- unsigned int bestFarBucket = maxbucketindex;
245
-
246
- bool foundAnswer = false;
247
- unsigned int bins = unconfTxs.size();
248
- bool newBucketRange = true;
249
- bool passing = true;
250
- EstimatorBucket passBucket;
251
- EstimatorBucket failBucket;
252
-
253
- // Start counting from highest feerate transactions
254
- for (int bucket = maxbucketindex; bucket >= 0; --bucket) {
255
- if (newBucketRange) {
256
- curNearBucket = bucket;
257
- newBucketRange = false;
258
- }
259
- curFarBucket = bucket;
260
- nConf += confAvg[periodTarget - 1][bucket];
261
- totalNum += txCtAvg[bucket];
262
- failNum += failAvg[periodTarget - 1][bucket];
263
- for (unsigned int confct = confTarget; confct < GetMaxConfirms(); confct++)
264
- extraNum += unconfTxs[(nBlockHeight - confct) % bins][bucket];
265
- extraNum += oldUnconfTxs[bucket];
266
- // If we have enough transaction data points in this range of buckets,
267
- // we can test for success
268
- // (Only count the confirmed data points, so that each confirmation count
269
- // will be looking at the same amount of data and same bucket breaks)
270
- if (totalNum >= sufficientTxVal / (1 - decay)) {
271
- double curPct = nConf / (totalNum + failNum + extraNum);
272
-
273
- // Check to see if we are no longer getting confirmed at the success rate
274
- if (curPct < successBreakPoint) {
275
- if (passing == true) {
276
- // First time we hit a failure record the failed bucket
277
- unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
278
- unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
279
- failBucket.start = failMinBucket ? buckets[failMinBucket - 1] : 0;
280
- failBucket.end = buckets[failMaxBucket];
281
- failBucket.withinTarget = nConf;
282
- failBucket.totalConfirmed = totalNum;
283
- failBucket.inMempool = extraNum;
284
- failBucket.leftMempool = failNum;
285
- passing = false;
286
- }
287
- continue;
288
- }
289
- // Otherwise update the cumulative stats, and the bucket variables
290
- // and reset the counters
291
- else {
292
- failBucket = EstimatorBucket(); // Reset any failed bucket, currently passing
293
- foundAnswer = true;
294
- passing = true;
295
- passBucket.withinTarget = nConf;
296
- nConf = 0;
297
- passBucket.totalConfirmed = totalNum;
298
- totalNum = 0;
299
- passBucket.inMempool = extraNum;
300
- passBucket.leftMempool = failNum;
301
- failNum = 0;
302
- extraNum = 0;
303
- bestNearBucket = curNearBucket;
304
- bestFarBucket = curFarBucket;
305
- newBucketRange = true;
306
- }
307
- }
308
- }
309
-
310
- double median = -1;
311
- double txSum = 0;
312
-
313
- // Calculate the "average" feerate of the best bucket range that met success conditions
314
- // Find the bucket with the median transaction and then report the average feerate from that bucket
315
- // This is a compromise between finding the median which we can't since we don't save all tx's
316
- // and reporting the average which is less accurate
317
- unsigned int minBucket = std::min(bestNearBucket, bestFarBucket);
318
- unsigned int maxBucket = std::max(bestNearBucket, bestFarBucket);
319
- for (unsigned int j = minBucket; j <= maxBucket; j++) {
320
- txSum += txCtAvg[j];
321
- }
322
- if (foundAnswer && txSum != 0) {
323
- txSum = txSum / 2;
324
- for (unsigned int j = minBucket; j <= maxBucket; j++) {
325
- if (txCtAvg[j] < txSum)
326
- txSum -= txCtAvg[j];
327
- else { // we're in the right bucket
328
- median = m_feerate_avg[j] / txCtAvg[j];
329
- break;
330
- }
331
- }
332
-
333
- passBucket.start = minBucket ? buckets[minBucket-1] : 0;
334
- passBucket.end = buckets[maxBucket];
335
- }
336
-
337
- // If we were passing until we reached last few buckets with insufficient data, then report those as failed
338
- if (passing && !newBucketRange) {
339
- unsigned int failMinBucket = std::min(curNearBucket, curFarBucket);
340
- unsigned int failMaxBucket = std::max(curNearBucket, curFarBucket);
341
- failBucket.start = failMinBucket ? buckets[failMinBucket - 1] : 0;
342
- failBucket.end = buckets[failMaxBucket];
343
- failBucket.withinTarget = nConf;
344
- failBucket.totalConfirmed = totalNum;
345
- failBucket.inMempool = extraNum;
346
- failBucket.leftMempool = failNum;
347
- }
348
-
349
- float passed_within_target_perc = 0.0;
350
- float failed_within_target_perc = 0.0;
351
- if ((passBucket.totalConfirmed + passBucket.inMempool + passBucket.leftMempool)) {
352
- passed_within_target_perc = 100 * passBucket.withinTarget / (passBucket.totalConfirmed + passBucket.inMempool + passBucket.leftMempool);
353
- }
354
- if ((failBucket.totalConfirmed + failBucket.inMempool + failBucket.leftMempool)) {
355
- failed_within_target_perc = 100 * failBucket.withinTarget / (failBucket.totalConfirmed + failBucket.inMempool + failBucket.leftMempool);
356
- }
357
-
358
- LogPrint(BCLog::ESTIMATEFEE, "FeeEst: %d > %.0f%% decay %.5f: feerate: %g from (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n",
359
- confTarget, 100.0 * successBreakPoint, decay,
360
- median, passBucket.start, passBucket.end,
361
- passed_within_target_perc,
362
- passBucket.withinTarget, passBucket.totalConfirmed, passBucket.inMempool, passBucket.leftMempool,
363
- failBucket.start, failBucket.end,
364
- failed_within_target_perc,
365
- failBucket.withinTarget, failBucket.totalConfirmed, failBucket.inMempool, failBucket.leftMempool);
366
-
367
-
368
- if (result) {
369
- result->pass = passBucket;
370
- result->fail = failBucket;
371
- result->decay = decay;
372
- result->scale = scale;
373
- }
374
- return median;
375
- }
376
-
377
- void TxConfirmStats::Write(CAutoFile& fileout) const
378
- {
379
- fileout << Using<EncodedDoubleFormatter>(decay);
380
- fileout << scale;
381
- fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(m_feerate_avg);
382
- fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(txCtAvg);
383
- fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(confAvg);
384
- fileout << Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(failAvg);
385
- }
386
-
387
- void TxConfirmStats::Read(CAutoFile& filein, int nFileVersion, size_t numBuckets)
388
- {
389
- // Read data file and do some very basic sanity checking
390
- // buckets and bucketMap are not updated yet, so don't access them
391
- // If there is a read failure, we'll just discard this entire object anyway
392
- size_t maxConfirms, maxPeriods;
393
-
394
- // The current version will store the decay with each individual TxConfirmStats and also keep a scale factor
395
- filein >> Using<EncodedDoubleFormatter>(decay);
396
- if (decay <= 0 || decay >= 1) {
397
- throw std::runtime_error("Corrupt estimates file. Decay must be between 0 and 1 (non-inclusive)");
398
- }
399
- filein >> scale;
400
- if (scale == 0) {
401
- throw std::runtime_error("Corrupt estimates file. Scale must be non-zero");
402
- }
403
-
404
- filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(m_feerate_avg);
405
- if (m_feerate_avg.size() != numBuckets) {
406
- throw std::runtime_error("Corrupt estimates file. Mismatch in feerate average bucket count");
407
- }
408
- filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(txCtAvg);
409
- if (txCtAvg.size() != numBuckets) {
410
- throw std::runtime_error("Corrupt estimates file. Mismatch in tx count bucket count");
411
- }
412
- filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(confAvg);
413
- maxPeriods = confAvg.size();
414
- maxConfirms = scale * maxPeriods;
415
-
416
- if (maxConfirms <= 0 || maxConfirms > 6 * 24 * 7) { // one week
417
- throw std::runtime_error("Corrupt estimates file. Must maintain estimates for between 1 and 1008 (one week) confirms");
418
- }
419
- for (unsigned int i = 0; i < maxPeriods; i++) {
420
- if (confAvg[i].size() != numBuckets) {
421
- throw std::runtime_error("Corrupt estimates file. Mismatch in feerate conf average bucket count");
422
- }
423
- }
424
-
425
- filein >> Using<VectorFormatter<VectorFormatter<EncodedDoubleFormatter>>>(failAvg);
426
- if (maxPeriods != failAvg.size()) {
427
- throw std::runtime_error("Corrupt estimates file. Mismatch in confirms tracked for failures");
428
- }
429
- for (unsigned int i = 0; i < maxPeriods; i++) {
430
- if (failAvg[i].size() != numBuckets) {
431
- throw std::runtime_error("Corrupt estimates file. Mismatch in one of failure average bucket counts");
432
- }
433
- }
434
-
435
- // Resize the current block variables which aren't stored in the data file
436
- // to match the number of confirms and buckets
437
- resizeInMemoryCounters(numBuckets);
438
-
439
- LogPrint(BCLog::ESTIMATEFEE, "Reading estimates: %u buckets counting confirms up to %u blocks\n",
440
- numBuckets, maxConfirms);
441
- }
442
-
443
- unsigned int TxConfirmStats::NewTx(unsigned int nBlockHeight, double val)
444
- {
445
- unsigned int bucketindex = bucketMap.lower_bound(val)->second;
446
- unsigned int blockIndex = nBlockHeight % unconfTxs.size();
447
- unconfTxs[blockIndex][bucketindex]++;
448
- return bucketindex;
449
- }
450
-
451
- void TxConfirmStats::removeTx(unsigned int entryHeight, unsigned int nBestSeenHeight, unsigned int bucketindex, bool inBlock)
452
- {
453
- //nBestSeenHeight is not updated yet for the new block
454
- int blocksAgo = nBestSeenHeight - entryHeight;
455
- if (nBestSeenHeight == 0) // the BlockPolicyEstimator hasn't seen any blocks yet
456
- blocksAgo = 0;
457
- if (blocksAgo < 0) {
458
- LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error, blocks ago is negative for mempool tx\n");
459
- return; //This can't happen because we call this with our best seen height, no entries can have higher
460
- }
461
-
462
- if (blocksAgo >= (int)unconfTxs.size()) {
463
- if (oldUnconfTxs[bucketindex] > 0) {
464
- oldUnconfTxs[bucketindex]--;
465
- } else {
466
- LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error, mempool tx removed from >25 blocks,bucketIndex=%u already\n",
467
- bucketindex);
468
- }
469
- }
470
- else {
471
- unsigned int blockIndex = entryHeight % unconfTxs.size();
472
- if (unconfTxs[blockIndex][bucketindex] > 0) {
473
- unconfTxs[blockIndex][bucketindex]--;
474
- } else {
475
- LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error, mempool tx removed from blockIndex=%u,bucketIndex=%u already\n",
476
- blockIndex, bucketindex);
477
- }
478
- }
479
- if (!inBlock && (unsigned int)blocksAgo >= scale) { // Only counts as a failure if not confirmed for entire period
480
- assert(scale != 0);
481
- unsigned int periodsAgo = blocksAgo / scale;
482
- for (size_t i = 0; i < periodsAgo && i < failAvg.size(); i++) {
483
- failAvg[i][bucketindex]++;
484
- }
485
- }
486
- }
487
-
488
- // This function is called from CTxMemPool::removeUnchecked to ensure
489
- // txs removed from the mempool for any reason are no longer
490
- // tracked. Txs that were part of a block have already been removed in
491
- // processBlockTx to ensure they are never double tracked, but it is
492
- // of no harm to try to remove them again.
493
- bool CBlockPolicyEstimator::removeTx(uint256 hash, bool inBlock)
494
- {
495
- LOCK(m_cs_fee_estimator);
496
- return _removeTx(hash, inBlock);
497
- }
498
-
499
- bool CBlockPolicyEstimator::_removeTx(const uint256& hash, bool inBlock)
500
- {
501
- AssertLockHeld(m_cs_fee_estimator);
502
- std::map<uint256, TxStatsInfo>::iterator pos = mapMemPoolTxs.find(hash);
503
- if (pos != mapMemPoolTxs.end()) {
504
- feeStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
505
- shortStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
506
- longStats->removeTx(pos->second.blockHeight, nBestSeenHeight, pos->second.bucketIndex, inBlock);
507
- mapMemPoolTxs.erase(hash);
508
- return true;
509
- } else {
510
- return false;
511
- }
512
- }
513
-
514
- CBlockPolicyEstimator::CBlockPolicyEstimator()
515
- : nBestSeenHeight(0), firstRecordedHeight(0), historicalFirst(0), historicalBest(0), trackedTxs(0), untrackedTxs(0)
516
- {
517
- static_assert(MIN_BUCKET_FEERATE > 0, "Min feerate must be nonzero");
518
- size_t bucketIndex = 0;
519
-
520
- for (double bucketBoundary = MIN_BUCKET_FEERATE; bucketBoundary <= MAX_BUCKET_FEERATE; bucketBoundary *= FEE_SPACING, bucketIndex++) {
521
- buckets.push_back(bucketBoundary);
522
- bucketMap[bucketBoundary] = bucketIndex;
523
- }
524
- buckets.push_back(INF_FEERATE);
525
- bucketMap[INF_FEERATE] = bucketIndex;
526
- assert(bucketMap.size() == buckets.size());
527
-
528
- feeStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
529
- shortStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
530
- longStats = std::unique_ptr<TxConfirmStats>(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
531
-
532
- // If the fee estimation file is present, read recorded estimations
533
- fs::path est_filepath = gArgs.GetDataDirNet() / FEE_ESTIMATES_FILENAME;
534
- CAutoFile est_file(fsbridge::fopen(est_filepath, "rb"), SER_DISK, CLIENT_VERSION);
535
- if (est_file.IsNull() || !Read(est_file)) {
536
- LogPrintf("Failed to read fee estimates from %s. Continue anyway.\n", fs::PathToString(est_filepath));
537
- }
538
- }
539
-
540
- CBlockPolicyEstimator::~CBlockPolicyEstimator()
541
- {
542
- }
543
-
544
- void CBlockPolicyEstimator::processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)
545
- {
546
- LOCK(m_cs_fee_estimator);
547
- unsigned int txHeight = entry.GetHeight();
548
- uint256 hash = entry.GetTx().GetHash();
549
- if (mapMemPoolTxs.count(hash)) {
550
- LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error mempool tx %s already being tracked\n",
551
- hash.ToString());
552
- return;
553
- }
554
-
555
- if (txHeight != nBestSeenHeight) {
556
- // Ignore side chains and re-orgs; assuming they are random they don't
557
- // affect the estimate. We'll potentially double count transactions in 1-block reorgs.
558
- // Ignore txs if BlockPolicyEstimator is not in sync with ActiveChain().Tip().
559
- // It will be synced next time a block is processed.
560
- return;
561
- }
562
-
563
- // Only want to be updating estimates when our blockchain is synced,
564
- // otherwise we'll miscalculate how many blocks its taking to get included.
565
- if (!validFeeEstimate) {
566
- untrackedTxs++;
567
- return;
568
- }
569
- trackedTxs++;
570
-
571
- // Feerates are stored and reported as BTC-per-kb:
572
- CFeeRate feeRate(entry.GetFee(), entry.GetTxSize());
573
-
574
- mapMemPoolTxs[hash].blockHeight = txHeight;
575
- unsigned int bucketIndex = feeStats->NewTx(txHeight, (double)feeRate.GetFeePerK());
576
- mapMemPoolTxs[hash].bucketIndex = bucketIndex;
577
- unsigned int bucketIndex2 = shortStats->NewTx(txHeight, (double)feeRate.GetFeePerK());
578
- assert(bucketIndex == bucketIndex2);
579
- unsigned int bucketIndex3 = longStats->NewTx(txHeight, (double)feeRate.GetFeePerK());
580
- assert(bucketIndex == bucketIndex3);
581
- }
582
-
583
- bool CBlockPolicyEstimator::processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry)
584
- {
585
- AssertLockHeld(m_cs_fee_estimator);
586
- if (!_removeTx(entry->GetTx().GetHash(), true)) {
587
- // This transaction wasn't being tracked for fee estimation
588
- return false;
589
- }
590
-
591
- // How many blocks did it take for miners to include this transaction?
592
- // blocksToConfirm is 1-based, so a transaction included in the earliest
593
- // possible block has confirmation count of 1
594
- int blocksToConfirm = nBlockHeight - entry->GetHeight();
595
- if (blocksToConfirm <= 0) {
596
- // This can't happen because we don't process transactions from a block with a height
597
- // lower than our greatest seen height
598
- LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy error Transaction had negative blocksToConfirm\n");
599
- return false;
600
- }
601
-
602
- // Feerates are stored and reported as BTC-per-kb:
603
- CFeeRate feeRate(entry->GetFee(), entry->GetTxSize());
604
-
605
- feeStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());
606
- shortStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());
607
- longStats->Record(blocksToConfirm, (double)feeRate.GetFeePerK());
608
- return true;
609
- }
610
-
611
- void CBlockPolicyEstimator::processBlock(unsigned int nBlockHeight,
612
- std::vector<const CTxMemPoolEntry*>& entries)
613
- {
614
- LOCK(m_cs_fee_estimator);
615
- if (nBlockHeight <= nBestSeenHeight) {
616
- // Ignore side chains and re-orgs; assuming they are random
617
- // they don't affect the estimate.
618
- // And if an attacker can re-org the chain at will, then
619
- // you've got much bigger problems than "attacker can influence
620
- // transaction fees."
621
- return;
622
- }
623
-
624
- // Must update nBestSeenHeight in sync with ClearCurrent so that
625
- // calls to removeTx (via processBlockTx) correctly calculate age
626
- // of unconfirmed txs to remove from tracking.
627
- nBestSeenHeight = nBlockHeight;
628
-
629
- // Update unconfirmed circular buffer
630
- feeStats->ClearCurrent(nBlockHeight);
631
- shortStats->ClearCurrent(nBlockHeight);
632
- longStats->ClearCurrent(nBlockHeight);
633
-
634
- // Decay all exponential averages
635
- feeStats->UpdateMovingAverages();
636
- shortStats->UpdateMovingAverages();
637
- longStats->UpdateMovingAverages();
638
-
639
- unsigned int countedTxs = 0;
640
- // Update averages with data points from current block
641
- for (const auto& entry : entries) {
642
- if (processBlockTx(nBlockHeight, entry))
643
- countedTxs++;
644
- }
645
-
646
- if (firstRecordedHeight == 0 && countedTxs > 0) {
647
- firstRecordedHeight = nBestSeenHeight;
648
- LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy first recorded height %u\n", firstRecordedHeight);
649
- }
650
-
651
-
652
- LogPrint(BCLog::ESTIMATEFEE, "Blockpolicy estimates updated by %u of %u block txs, since last block %u of %u tracked, mempool map size %u, max target %u from %s\n",
653
- countedTxs, entries.size(), trackedTxs, trackedTxs + untrackedTxs, mapMemPoolTxs.size(),
654
- MaxUsableEstimate(), HistoricalBlockSpan() > BlockSpan() ? "historical" : "current");
655
-
656
- trackedTxs = 0;
657
- untrackedTxs = 0;
658
- }
659
-
660
- CFeeRate CBlockPolicyEstimator::estimateFee(int confTarget) const
661
- {
662
- // It's not possible to get reasonable estimates for confTarget of 1
663
- if (confTarget <= 1)
664
- return CFeeRate(0);
665
-
666
- return estimateRawFee(confTarget, DOUBLE_SUCCESS_PCT, FeeEstimateHorizon::MED_HALFLIFE);
667
- }
668
-
669
- CFeeRate CBlockPolicyEstimator::estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon, EstimationResult* result) const
670
- {
671
- TxConfirmStats* stats = nullptr;
672
- double sufficientTxs = SUFFICIENT_FEETXS;
673
- switch (horizon) {
674
- case FeeEstimateHorizon::SHORT_HALFLIFE: {
675
- stats = shortStats.get();
676
- sufficientTxs = SUFFICIENT_TXS_SHORT;
677
- break;
678
- }
679
- case FeeEstimateHorizon::MED_HALFLIFE: {
680
- stats = feeStats.get();
681
- break;
682
- }
683
- case FeeEstimateHorizon::LONG_HALFLIFE: {
684
- stats = longStats.get();
685
- break;
686
- }
687
- } // no default case, so the compiler can warn about missing cases
688
- assert(stats);
689
-
690
- LOCK(m_cs_fee_estimator);
691
- // Return failure if trying to analyze a target we're not tracking
692
- if (confTarget <= 0 || (unsigned int)confTarget > stats->GetMaxConfirms())
693
- return CFeeRate(0);
694
- if (successThreshold > 1)
695
- return CFeeRate(0);
696
-
697
- double median = stats->EstimateMedianVal(confTarget, sufficientTxs, successThreshold, nBestSeenHeight, result);
698
-
699
- if (median < 0)
700
- return CFeeRate(0);
701
-
702
- return CFeeRate(llround(median));
703
- }
704
-
705
- unsigned int CBlockPolicyEstimator::HighestTargetTracked(FeeEstimateHorizon horizon) const
706
- {
707
- LOCK(m_cs_fee_estimator);
708
- switch (horizon) {
709
- case FeeEstimateHorizon::SHORT_HALFLIFE: {
710
- return shortStats->GetMaxConfirms();
711
- }
712
- case FeeEstimateHorizon::MED_HALFLIFE: {
713
- return feeStats->GetMaxConfirms();
714
- }
715
- case FeeEstimateHorizon::LONG_HALFLIFE: {
716
- return longStats->GetMaxConfirms();
717
- }
718
- } // no default case, so the compiler can warn about missing cases
719
- assert(false);
720
- }
721
-
722
- unsigned int CBlockPolicyEstimator::BlockSpan() const
723
- {
724
- if (firstRecordedHeight == 0) return 0;
725
- assert(nBestSeenHeight >= firstRecordedHeight);
726
-
727
- return nBestSeenHeight - firstRecordedHeight;
728
- }
729
-
730
- unsigned int CBlockPolicyEstimator::HistoricalBlockSpan() const
731
- {
732
- if (historicalFirst == 0) return 0;
733
- assert(historicalBest >= historicalFirst);
734
-
735
- if (nBestSeenHeight - historicalBest > OLDEST_ESTIMATE_HISTORY) return 0;
736
-
737
- return historicalBest - historicalFirst;
738
- }
739
-
740
- unsigned int CBlockPolicyEstimator::MaxUsableEstimate() const
741
- {
742
- // Block spans are divided by 2 to make sure there are enough potential failing data points for the estimate
743
- return std::min(longStats->GetMaxConfirms(), std::max(BlockSpan(), HistoricalBlockSpan()) / 2);
744
- }
745
-
746
- /** Return a fee estimate at the required successThreshold from the shortest
747
- * time horizon which tracks confirmations up to the desired target. If
748
- * checkShorterHorizon is requested, also allow short time horizon estimates
749
- * for a lower target to reduce the given answer */
750
- double CBlockPolicyEstimator::estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const
751
- {
752
- double estimate = -1;
753
- if (confTarget >= 1 && confTarget <= longStats->GetMaxConfirms()) {
754
- // Find estimate from shortest time horizon possible
755
- if (confTarget <= shortStats->GetMaxConfirms()) { // short horizon
756
- estimate = shortStats->EstimateMedianVal(confTarget, SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, result);
757
- }
758
- else if (confTarget <= feeStats->GetMaxConfirms()) { // medium horizon
759
- estimate = feeStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
760
- }
761
- else { // long horizon
762
- estimate = longStats->EstimateMedianVal(confTarget, SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, result);
763
- }
764
- if (checkShorterHorizon) {
765
- EstimationResult tempResult;
766
- // If a lower confTarget from a more recent horizon returns a lower answer use it.
767
- if (confTarget > feeStats->GetMaxConfirms()) {
768
- double medMax = feeStats->EstimateMedianVal(feeStats->GetMaxConfirms(), SUFFICIENT_FEETXS, successThreshold, nBestSeenHeight, &tempResult);
769
- if (medMax > 0 && (estimate == -1 || medMax < estimate)) {
770
- estimate = medMax;
771
- if (result) *result = tempResult;
772
- }
773
- }
774
- if (confTarget > shortStats->GetMaxConfirms()) {
775
- double shortMax = shortStats->EstimateMedianVal(shortStats->GetMaxConfirms(), SUFFICIENT_TXS_SHORT, successThreshold, nBestSeenHeight, &tempResult);
776
- if (shortMax > 0 && (estimate == -1 || shortMax < estimate)) {
777
- estimate = shortMax;
778
- if (result) *result = tempResult;
779
- }
780
- }
781
- }
782
- }
783
- return estimate;
784
- }
785
-
786
- /** Ensure that for a conservative estimate, the DOUBLE_SUCCESS_PCT is also met
787
- * at 2 * target for any longer time horizons.
788
- */
789
- double CBlockPolicyEstimator::estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const
790
- {
791
- double estimate = -1;
792
- EstimationResult tempResult;
793
- if (doubleTarget <= shortStats->GetMaxConfirms()) {
794
- estimate = feeStats->EstimateMedianVal(doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, nBestSeenHeight, result);
795
- }
796
- if (doubleTarget <= feeStats->GetMaxConfirms()) {
797
- double longEstimate = longStats->EstimateMedianVal(doubleTarget, SUFFICIENT_FEETXS, DOUBLE_SUCCESS_PCT, nBestSeenHeight, &tempResult);
798
- if (longEstimate > estimate) {
799
- estimate = longEstimate;
800
- if (result) *result = tempResult;
801
- }
802
- }
803
- return estimate;
804
- }
805
-
806
- /** estimateSmartFee returns the max of the feerates calculated with a 60%
807
- * threshold required at target / 2, an 85% threshold required at target and a
808
- * 95% threshold required at 2 * target. Each calculation is performed at the
809
- * shortest time horizon which tracks the required target. Conservative
810
- * estimates, however, required the 95% threshold at 2 * target be met for any
811
- * longer time horizons also.
812
- */
813
- CFeeRate CBlockPolicyEstimator::estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const
814
- {
815
- LOCK(m_cs_fee_estimator);
816
-
817
- if (feeCalc) {
818
- feeCalc->desiredTarget = confTarget;
819
- feeCalc->returnedTarget = confTarget;
820
- }
821
-
822
- double median = -1;
823
- EstimationResult tempResult;
824
-
825
- // Return failure if trying to analyze a target we're not tracking
826
- if (confTarget <= 0 || (unsigned int)confTarget > longStats->GetMaxConfirms()) {
827
- return CFeeRate(0); // error condition
828
- }
829
-
830
- // It's not possible to get reasonable estimates for confTarget of 1
831
- if (confTarget == 1) confTarget = 2;
832
-
833
- unsigned int maxUsableEstimate = MaxUsableEstimate();
834
- if ((unsigned int)confTarget > maxUsableEstimate) {
835
- confTarget = maxUsableEstimate;
836
- }
837
- if (feeCalc) feeCalc->returnedTarget = confTarget;
838
-
839
- if (confTarget <= 1) return CFeeRate(0); // error condition
840
-
841
- assert(confTarget > 0); //estimateCombinedFee and estimateConservativeFee take unsigned ints
842
- /** true is passed to estimateCombined fee for target/2 and target so
843
- * that we check the max confirms for shorter time horizons as well.
844
- * This is necessary to preserve monotonically increasing estimates.
845
- * For non-conservative estimates we do the same thing for 2*target, but
846
- * for conservative estimates we want to skip these shorter horizons
847
- * checks for 2*target because we are taking the max over all time
848
- * horizons so we already have monotonically increasing estimates and
849
- * the purpose of conservative estimates is not to let short term
850
- * fluctuations lower our estimates by too much.
851
- */
852
- double halfEst = estimateCombinedFee(confTarget/2, HALF_SUCCESS_PCT, true, &tempResult);
853
- if (feeCalc) {
854
- feeCalc->est = tempResult;
855
- feeCalc->reason = FeeReason::HALF_ESTIMATE;
856
- }
857
- median = halfEst;
858
- double actualEst = estimateCombinedFee(confTarget, SUCCESS_PCT, true, &tempResult);
859
- if (actualEst > median) {
860
- median = actualEst;
861
- if (feeCalc) {
862
- feeCalc->est = tempResult;
863
- feeCalc->reason = FeeReason::FULL_ESTIMATE;
864
- }
865
- }
866
- double doubleEst = estimateCombinedFee(2 * confTarget, DOUBLE_SUCCESS_PCT, !conservative, &tempResult);
867
- if (doubleEst > median) {
868
- median = doubleEst;
869
- if (feeCalc) {
870
- feeCalc->est = tempResult;
871
- feeCalc->reason = FeeReason::DOUBLE_ESTIMATE;
872
- }
873
- }
874
-
875
- if (conservative || median == -1) {
876
- double consEst = estimateConservativeFee(2 * confTarget, &tempResult);
877
- if (consEst > median) {
878
- median = consEst;
879
- if (feeCalc) {
880
- feeCalc->est = tempResult;
881
- feeCalc->reason = FeeReason::CONSERVATIVE;
882
- }
883
- }
884
- }
885
-
886
- if (median < 0) return CFeeRate(0); // error condition
887
-
888
- return CFeeRate(llround(median));
889
- }
890
-
891
- void CBlockPolicyEstimator::Flush() {
892
- FlushUnconfirmed();
893
-
894
- fs::path est_filepath = gArgs.GetDataDirNet() / FEE_ESTIMATES_FILENAME;
895
- CAutoFile est_file(fsbridge::fopen(est_filepath, "wb"), SER_DISK, CLIENT_VERSION);
896
- if (est_file.IsNull() || !Write(est_file)) {
897
- LogPrintf("Failed to write fee estimates to %s. Continue anyway.\n", fs::PathToString(est_filepath));
898
- }
899
- }
900
-
901
- bool CBlockPolicyEstimator::Write(CAutoFile& fileout) const
902
- {
903
- try {
904
- LOCK(m_cs_fee_estimator);
905
- fileout << 149900; // version required to read: 0.14.99 or later
906
- fileout << CLIENT_VERSION; // version that wrote the file
907
- fileout << nBestSeenHeight;
908
- if (BlockSpan() > HistoricalBlockSpan()/2) {
909
- fileout << firstRecordedHeight << nBestSeenHeight;
910
- }
911
- else {
912
- fileout << historicalFirst << historicalBest;
913
- }
914
- fileout << Using<VectorFormatter<EncodedDoubleFormatter>>(buckets);
915
- feeStats->Write(fileout);
916
- shortStats->Write(fileout);
917
- longStats->Write(fileout);
918
- }
919
- catch (const std::exception&) {
920
- LogPrintf("CBlockPolicyEstimator::Write(): unable to write policy estimator data (non-fatal)\n");
921
- return false;
922
- }
923
- return true;
924
- }
925
-
926
- bool CBlockPolicyEstimator::Read(CAutoFile& filein)
927
- {
928
- try {
929
- LOCK(m_cs_fee_estimator);
930
- int nVersionRequired, nVersionThatWrote;
931
- filein >> nVersionRequired >> nVersionThatWrote;
932
- if (nVersionRequired > CLIENT_VERSION) {
933
- throw std::runtime_error(strprintf("up-version (%d) fee estimate file", nVersionRequired));
934
- }
935
-
936
- // Read fee estimates file into temporary variables so existing data
937
- // structures aren't corrupted if there is an exception.
938
- unsigned int nFileBestSeenHeight;
939
- filein >> nFileBestSeenHeight;
940
-
941
- if (nVersionRequired < 149900) {
942
- LogPrintf("%s: incompatible old fee estimation data (non-fatal). Version: %d\n", __func__, nVersionRequired);
943
- } else { // New format introduced in 149900
944
- unsigned int nFileHistoricalFirst, nFileHistoricalBest;
945
- filein >> nFileHistoricalFirst >> nFileHistoricalBest;
946
- if (nFileHistoricalFirst > nFileHistoricalBest || nFileHistoricalBest > nFileBestSeenHeight) {
947
- throw std::runtime_error("Corrupt estimates file. Historical block range for estimates is invalid");
948
- }
949
- std::vector<double> fileBuckets;
950
- filein >> Using<VectorFormatter<EncodedDoubleFormatter>>(fileBuckets);
951
- size_t numBuckets = fileBuckets.size();
952
- if (numBuckets <= 1 || numBuckets > 1000) {
953
- throw std::runtime_error("Corrupt estimates file. Must have between 2 and 1000 feerate buckets");
954
- }
955
-
956
- std::unique_ptr<TxConfirmStats> fileFeeStats(new TxConfirmStats(buckets, bucketMap, MED_BLOCK_PERIODS, MED_DECAY, MED_SCALE));
957
- std::unique_ptr<TxConfirmStats> fileShortStats(new TxConfirmStats(buckets, bucketMap, SHORT_BLOCK_PERIODS, SHORT_DECAY, SHORT_SCALE));
958
- std::unique_ptr<TxConfirmStats> fileLongStats(new TxConfirmStats(buckets, bucketMap, LONG_BLOCK_PERIODS, LONG_DECAY, LONG_SCALE));
959
- fileFeeStats->Read(filein, nVersionThatWrote, numBuckets);
960
- fileShortStats->Read(filein, nVersionThatWrote, numBuckets);
961
- fileLongStats->Read(filein, nVersionThatWrote, numBuckets);
962
-
963
- // Fee estimates file parsed correctly
964
- // Copy buckets from file and refresh our bucketmap
965
- buckets = fileBuckets;
966
- bucketMap.clear();
967
- for (unsigned int i = 0; i < buckets.size(); i++) {
968
- bucketMap[buckets[i]] = i;
969
- }
970
-
971
- // Destroy old TxConfirmStats and point to new ones that already reference buckets and bucketMap
972
- feeStats = std::move(fileFeeStats);
973
- shortStats = std::move(fileShortStats);
974
- longStats = std::move(fileLongStats);
975
-
976
- nBestSeenHeight = nFileBestSeenHeight;
977
- historicalFirst = nFileHistoricalFirst;
978
- historicalBest = nFileHistoricalBest;
979
- }
980
- }
981
- catch (const std::exception& e) {
982
- LogPrintf("CBlockPolicyEstimator::Read(): unable to read policy estimator data (non-fatal): %s\n",e.what());
983
- return false;
984
- }
985
- return true;
986
- }
987
-
988
- void CBlockPolicyEstimator::FlushUnconfirmed() {
989
- int64_t startclear = GetTimeMicros();
990
- LOCK(m_cs_fee_estimator);
991
- size_t num_entries = mapMemPoolTxs.size();
992
- // Remove every entry in mapMemPoolTxs
993
- while (!mapMemPoolTxs.empty()) {
994
- auto mi = mapMemPoolTxs.begin();
995
- _removeTx(mi->first, false); // this calls erase() on mapMemPoolTxs
996
- }
997
- int64_t endclear = GetTimeMicros();
998
- LogPrint(BCLog::ESTIMATEFEE, "Recorded %u unconfirmed txs from mempool in %gs\n", num_entries, (endclear - startclear)*0.000001);
999
- }
1000
-
1001
- FeeFilterRounder::FeeFilterRounder(const CFeeRate& minIncrementalFee)
1002
- {
1003
- CAmount minFeeLimit = std::max(CAmount(1), minIncrementalFee.GetFeePerK() / 2);
1004
- feeset.insert(0);
1005
- for (double bucketBoundary = minFeeLimit; bucketBoundary <= MAX_FILTER_FEERATE; bucketBoundary *= FEE_FILTER_SPACING) {
1006
- feeset.insert(bucketBoundary);
1007
- }
1008
- }
1009
-
1010
- CAmount FeeFilterRounder::round(CAmount currentMinFee)
1011
- {
1012
- std::set<double>::iterator it = feeset.lower_bound(currentMinFee);
1013
- if ((it != feeset.begin() && insecure_rand.rand32() % 3 != 0) || it == feeset.end()) {
1014
- it--;
1015
- }
1016
- return static_cast<CAmount>(*it);
1017
- }
src/policy/fees.h DELETED
@@ -1,310 +0,0 @@
1
- // Copyright (c) 2009-2010 Satoshi Nakamoto
2
- // Copyright (c) 2009-2021 The Bitcoin Core developers
3
- // Distributed under the MIT software license, see the accompanying
4
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
- #ifndef BITCOIN_POLICY_FEES_H
6
- #define BITCOIN_POLICY_FEES_H
7
-
8
- #include <consensus/amount.h>
9
- #include <policy/feerate.h>
10
- #include <uint256.h>
11
- #include <random.h>
12
- #include <sync.h>
13
-
14
- #include <array>
15
- #include <map>
16
- #include <memory>
17
- #include <string>
18
- #include <vector>
19
-
20
- class CAutoFile;
21
- class CFeeRate;
22
- class CTxMemPoolEntry;
23
- class CTxMemPool;
24
- class TxConfirmStats;
25
-
26
- /* Identifier for each of the 3 different TxConfirmStats which will track
27
- * history over different time horizons. */
28
- enum class FeeEstimateHorizon {
29
- SHORT_HALFLIFE,
30
- MED_HALFLIFE,
31
- LONG_HALFLIFE,
32
- };
33
-
34
- static constexpr auto ALL_FEE_ESTIMATE_HORIZONS = std::array{
35
- FeeEstimateHorizon::SHORT_HALFLIFE,
36
- FeeEstimateHorizon::MED_HALFLIFE,
37
- FeeEstimateHorizon::LONG_HALFLIFE,
38
- };
39
-
40
- std::string StringForFeeEstimateHorizon(FeeEstimateHorizon horizon);
41
-
42
- /* Enumeration of reason for returned fee estimate */
43
- enum class FeeReason {
44
- NONE,
45
- HALF_ESTIMATE,
46
- FULL_ESTIMATE,
47
- DOUBLE_ESTIMATE,
48
- CONSERVATIVE,
49
- MEMPOOL_MIN,
50
- PAYTXFEE,
51
- FALLBACK,
52
- REQUIRED,
53
- };
54
-
55
- /* Used to return detailed information about a feerate bucket */
56
- struct EstimatorBucket
57
- {
58
- double start = -1;
59
- double end = -1;
60
- double withinTarget = 0;
61
- double totalConfirmed = 0;
62
- double inMempool = 0;
63
- double leftMempool = 0;
64
- };
65
-
66
- /* Used to return detailed information about a fee estimate calculation */
67
- struct EstimationResult
68
- {
69
- EstimatorBucket pass;
70
- EstimatorBucket fail;
71
- double decay = 0;
72
- unsigned int scale = 0;
73
- };
74
-
75
- struct FeeCalculation
76
- {
77
- EstimationResult est;
78
- FeeReason reason = FeeReason::NONE;
79
- int desiredTarget = 0;
80
- int returnedTarget = 0;
81
- };
82
-
83
- /** \class CBlockPolicyEstimator
84
- * The BlockPolicyEstimator is used for estimating the feerate needed
85
- * for a transaction to be included in a block within a certain number of
86
- * blocks.
87
- *
88
- * At a high level the algorithm works by grouping transactions into buckets
89
- * based on having similar feerates and then tracking how long it
90
- * takes transactions in the various buckets to be mined. It operates under
91
- * the assumption that in general transactions of higher feerate will be
92
- * included in blocks before transactions of lower feerate. So for
93
- * example if you wanted to know what feerate you should put on a transaction to
94
- * be included in a block within the next 5 blocks, you would start by looking
95
- * at the bucket with the highest feerate transactions and verifying that a
96
- * sufficiently high percentage of them were confirmed within 5 blocks and
97
- * then you would look at the next highest feerate bucket, and so on, stopping at
98
- * the last bucket to pass the test. The average feerate of transactions in this
99
- * bucket will give you an indication of the lowest feerate you can put on a
100
- * transaction and still have a sufficiently high chance of being confirmed
101
- * within your desired 5 blocks.
102
- *
103
- * Here is a brief description of the implementation:
104
- * When a transaction enters the mempool, we track the height of the block chain
105
- * at entry. All further calculations are conducted only on this set of "seen"
106
- * transactions. Whenever a block comes in, we count the number of transactions
107
- * in each bucket and the total amount of feerate paid in each bucket. Then we
108
- * calculate how many blocks Y it took each transaction to be mined. We convert
109
- * from a number of blocks to a number of periods Y' each encompassing "scale"
110
- * blocks. This is tracked in 3 different data sets each up to a maximum
111
- * number of periods. Within each data set we have an array of counters in each
112
- * feerate bucket and we increment all the counters from Y' up to max periods
113
- * representing that a tx was successfully confirmed in less than or equal to
114
- * that many periods. We want to save a history of this information, so at any
115
- * time we have a counter of the total number of transactions that happened in a
116
- * given feerate bucket and the total number that were confirmed in each of the
117
- * periods or less for any bucket. We save this history by keeping an
118
- * exponentially decaying moving average of each one of these stats. This is
119
- * done for a different decay in each of the 3 data sets to keep relevant data
120
- * from different time horizons. Furthermore we also keep track of the number
121
- * unmined (in mempool or left mempool without being included in a block)
122
- * transactions in each bucket and for how many blocks they have been
123
- * outstanding and use both of these numbers to increase the number of transactions
124
- * we've seen in that feerate bucket when calculating an estimate for any number
125
- * of confirmations below the number of blocks they've been outstanding.
126
- *
127
- * We want to be able to estimate feerates that are needed on tx's to be included in
128
- * a certain number of blocks. Every time a block is added to the best chain, this class records
129
- * stats on the transactions included in that block
130
- */
131
- class CBlockPolicyEstimator
132
- {
133
- private:
134
- /** Track confirm delays up to 12 blocks for short horizon */
135
- static constexpr unsigned int SHORT_BLOCK_PERIODS = 12;
136
- static constexpr unsigned int SHORT_SCALE = 1;
137
- /** Track confirm delays up to 48 blocks for medium horizon */
138
- static constexpr unsigned int MED_BLOCK_PERIODS = 24;
139
- static constexpr unsigned int MED_SCALE = 2;
140
- /** Track confirm delays up to 1008 blocks for long horizon */
141
- static constexpr unsigned int LONG_BLOCK_PERIODS = 42;
142
- static constexpr unsigned int LONG_SCALE = 24;
143
- /** Historical estimates that are older than this aren't valid */
144
- static const unsigned int OLDEST_ESTIMATE_HISTORY = 6 * 1008;
145
-
146
- /** Decay of .962 is a half-life of 18 blocks or about 3 hours */
147
- static constexpr double SHORT_DECAY = .962;
148
- /** Decay of .9952 is a half-life of 144 blocks or about 1 day */
149
- static constexpr double MED_DECAY = .9952;
150
- /** Decay of .99931 is a half-life of 1008 blocks or about 1 week */
151
- static constexpr double LONG_DECAY = .99931;
152
-
153
- /** Require greater than 60% of X feerate transactions to be confirmed within Y/2 blocks*/
154
- static constexpr double HALF_SUCCESS_PCT = .6;
155
- /** Require greater than 85% of X feerate transactions to be confirmed within Y blocks*/
156
- static constexpr double SUCCESS_PCT = .85;
157
- /** Require greater than 95% of X feerate transactions to be confirmed within 2 * Y blocks*/
158
- static constexpr double DOUBLE_SUCCESS_PCT = .95;
159
-
160
- /** Require an avg of 0.1 tx in the combined feerate bucket per block to have stat significance */
161
- static constexpr double SUFFICIENT_FEETXS = 0.1;
162
- /** Require an avg of 0.5 tx when using short decay since there are fewer blocks considered*/
163
- static constexpr double SUFFICIENT_TXS_SHORT = 0.5;
164
-
165
- /** Minimum and Maximum values for tracking feerates
166
- * The MIN_BUCKET_FEERATE should just be set to the lowest reasonable feerate we
167
- * might ever want to track. Historically this has been 1000 since it was
168
- * inheriting DEFAULT_MIN_RELAY_TX_FEE and changing it is disruptive as it
169
- * invalidates old estimates files. So leave it at 1000 unless it becomes
170
- * necessary to lower it, and then lower it substantially.
171
- */
172
- static constexpr double MIN_BUCKET_FEERATE = 1000;
173
- static constexpr double MAX_BUCKET_FEERATE = 1e7;
174
-
175
- /** Spacing of FeeRate buckets
176
- * We have to lump transactions into buckets based on feerate, but we want to be able
177
- * to give accurate estimates over a large range of potential feerates
178
- * Therefore it makes sense to exponentially space the buckets
179
- */
180
- static constexpr double FEE_SPACING = 1.05;
181
-
182
- public:
183
- /** Create new BlockPolicyEstimator and initialize stats tracking classes with default values */
184
- CBlockPolicyEstimator();
185
- ~CBlockPolicyEstimator();
186
-
187
- /** Process all the transactions that have been included in a block */
188
- void processBlock(unsigned int nBlockHeight,
189
- std::vector<const CTxMemPoolEntry*>& entries)
190
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
191
-
192
- /** Process a transaction accepted to the mempool*/
193
- void processTransaction(const CTxMemPoolEntry& entry, bool validFeeEstimate)
194
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
195
-
196
- /** Remove a transaction from the mempool tracking stats*/
197
- bool removeTx(uint256 hash, bool inBlock)
198
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
199
-
200
- /** DEPRECATED. Return a feerate estimate */
201
- CFeeRate estimateFee(int confTarget) const
202
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
203
-
204
- /** Estimate feerate needed to get be included in a block within confTarget
205
- * blocks. If no answer can be given at confTarget, return an estimate at
206
- * the closest target where one can be given. 'conservative' estimates are
207
- * valid over longer time horizons also.
208
- */
209
- CFeeRate estimateSmartFee(int confTarget, FeeCalculation *feeCalc, bool conservative) const
210
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
211
-
212
- /** Return a specific fee estimate calculation with a given success
213
- * threshold and time horizon, and optionally return detailed data about
214
- * calculation
215
- */
216
- CFeeRate estimateRawFee(int confTarget, double successThreshold, FeeEstimateHorizon horizon,
217
- EstimationResult* result = nullptr) const
218
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
219
-
220
- /** Write estimation data to a file */
221
- bool Write(CAutoFile& fileout) const
222
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
223
-
224
- /** Read estimation data from a file */
225
- bool Read(CAutoFile& filein)
226
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
227
-
228
- /** Empty mempool transactions on shutdown to record failure to confirm for txs still in mempool */
229
- void FlushUnconfirmed()
230
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
231
-
232
- /** Calculation of highest target that estimates are tracked for */
233
- unsigned int HighestTargetTracked(FeeEstimateHorizon horizon) const
234
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
235
-
236
- /** Drop still unconfirmed transactions and record current estimations, if the fee estimation file is present. */
237
- void Flush()
238
- EXCLUSIVE_LOCKS_REQUIRED(!m_cs_fee_estimator);
239
-
240
- private:
241
- mutable Mutex m_cs_fee_estimator;
242
-
243
- unsigned int nBestSeenHeight GUARDED_BY(m_cs_fee_estimator);
244
- unsigned int firstRecordedHeight GUARDED_BY(m_cs_fee_estimator);
245
- unsigned int historicalFirst GUARDED_BY(m_cs_fee_estimator);
246
- unsigned int historicalBest GUARDED_BY(m_cs_fee_estimator);
247
-
248
- struct TxStatsInfo
249
- {
250
- unsigned int blockHeight;
251
- unsigned int bucketIndex;
252
- TxStatsInfo() : blockHeight(0), bucketIndex(0) {}
253
- };
254
-
255
- // map of txids to information about that transaction
256
- std::map<uint256, TxStatsInfo> mapMemPoolTxs GUARDED_BY(m_cs_fee_estimator);
257
-
258
- /** Classes to track historical data on transaction confirmations */
259
- std::unique_ptr<TxConfirmStats> feeStats PT_GUARDED_BY(m_cs_fee_estimator);
260
- std::unique_ptr<TxConfirmStats> shortStats PT_GUARDED_BY(m_cs_fee_estimator);
261
- std::unique_ptr<TxConfirmStats> longStats PT_GUARDED_BY(m_cs_fee_estimator);
262
-
263
- unsigned int trackedTxs GUARDED_BY(m_cs_fee_estimator);
264
- unsigned int untrackedTxs GUARDED_BY(m_cs_fee_estimator);
265
-
266
- std::vector<double> buckets GUARDED_BY(m_cs_fee_estimator); // The upper-bound of the range for the bucket (inclusive)
267
- std::map<double, unsigned int> bucketMap GUARDED_BY(m_cs_fee_estimator); // Map of bucket upper-bound to index into all vectors by bucket
268
-
269
- /** Process a transaction confirmed in a block*/
270
- bool processBlockTx(unsigned int nBlockHeight, const CTxMemPoolEntry* entry) EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
271
-
272
- /** Helper for estimateSmartFee */
273
- double estimateCombinedFee(unsigned int confTarget, double successThreshold, bool checkShorterHorizon, EstimationResult *result) const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
274
- /** Helper for estimateSmartFee */
275
- double estimateConservativeFee(unsigned int doubleTarget, EstimationResult *result) const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
276
- /** Number of blocks of data recorded while fee estimates have been running */
277
- unsigned int BlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
278
- /** Number of blocks of recorded fee estimate data represented in saved data file */
279
- unsigned int HistoricalBlockSpan() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
280
- /** Calculation of highest target that reasonable estimate can be provided for */
281
- unsigned int MaxUsableEstimate() const EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
282
-
283
- /** A non-thread-safe helper for the removeTx function */
284
- bool _removeTx(const uint256& hash, bool inBlock)
285
- EXCLUSIVE_LOCKS_REQUIRED(m_cs_fee_estimator);
286
- };
287
-
288
- class FeeFilterRounder
289
- {
290
- private:
291
- static constexpr double MAX_FILTER_FEERATE = 1e7;
292
- /** FEE_FILTER_SPACING is just used to provide some quantization of fee
293
- * filter results. Historically it reused FEE_SPACING, but it is completely
294
- * unrelated, and was made a separate constant so the two concepts are not
295
- * tied together */
296
- static constexpr double FEE_FILTER_SPACING = 1.1;
297
-
298
- public:
299
- /** Create new FeeFilterRounder */
300
- explicit FeeFilterRounder(const CFeeRate& minIncrementalFee);
301
-
302
- /** Quantize a minimum fee for privacy purpose before broadcast. Not thread-safe due to use of FastRandomContext */
303
- CAmount round(CAmount currentMinFee);
304
-
305
- private:
306
- std::set<double> feeset;
307
- FastRandomContext insecure_rand;
308
- };
309
-
310
- #endif // BITCOIN_POLICY_FEES_H
src/policy/policy.cpp CHANGED
@@ -9,52 +9,9 @@
9
9
 
10
10
  #include <consensus/validation.h>
11
11
  #include <coins.h>
12
+ #include <kernel.h>
12
13
  #include <span.h>
13
14
 
14
- CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
15
- {
16
- // "Dust" is defined in terms of dustRelayFee,
17
- // which has units satoshis-per-kilobyte.
18
- // If you'd pay more in fees than the value of the output
19
- // to spend something, then we consider it dust.
20
- // A typical spendable non-segwit txout is 34 bytes big, and will
21
- // need a CTxIn of at least 148 bytes to spend:
22
- // so dust is a spendable txout less than
23
- // 182*dustRelayFee/1000 (in satoshis).
24
- // 546 satoshis at the default rate of 3000 sat/kvB.
25
- // A typical spendable segwit P2WPKH txout is 31 bytes big, and will
26
- // need a CTxIn of at least 67 bytes to spend:
27
- // so dust is a spendable txout less than
28
- // 98*dustRelayFee/1000 (in satoshis).
29
- // 294 satoshis at the default rate of 3000 sat/kvB.
30
- if (txout.scriptPubKey.IsUnspendable())
31
- return 0;
32
-
33
- size_t nSize = GetSerializeSize(txout);
34
- int witnessversion = 0;
35
- std::vector<unsigned char> witnessprogram;
36
-
37
- // Note this computation is for spending a Segwit v0 P2WPKH output (a 33 bytes
38
- // public key + an ECDSA signature). For Segwit v1 Taproot outputs the minimum
39
- // satisfaction is lower (a single BIP340 signature) but this computation was
40
- // kept to not further reduce the dust level.
41
- // See discussion in https://github.com/bitcoin/bitcoin/pull/22779 for details.
42
- if (txout.scriptPubKey.IsWitnessProgram(witnessversion, witnessprogram)) {
43
- // sum the sizes of the parts of a transaction input
44
- // with 75% segwit discount applied to the script size.
45
- nSize += (32 + 4 + 1 + (107 / WITNESS_SCALE_FACTOR) + 4);
46
- } else {
47
- nSize += (32 + 4 + 1 + 107 + 4); // the 148 mentioned above
48
- }
49
-
50
- return dustRelayFeeIn.GetFee(nSize);
51
- }
52
-
53
- bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFeeIn)
54
- {
55
- return (txout.nValue < GetDustThreshold(txout, dustRelayFeeIn));
56
- }
57
-
58
15
  bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType)
59
16
  {
60
17
  std::vector<std::vector<unsigned char> > vSolutions;
@@ -78,7 +35,7 @@ bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType)
78
35
  return true;
79
36
  }
80
37
 
81
- bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason)
38
+ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, std::string& reason)
82
39
  {
83
40
  if (tx.nVersion > TX_MAX_STANDARD_VERSION || tx.nVersion < 1) {
84
41
  reason = "version";
@@ -128,9 +85,6 @@ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeR
128
85
  else if ((whichType == TxoutType::MULTISIG) && (!permit_bare_multisig)) {
129
86
  reason = "bare-multisig";
130
87
  return false;
131
- } else if (IsDust(txout, dust_relay_fee)) {
132
- reason = "dust";
133
- return false;
134
88
  }
135
89
  }
136
90
 
src/policy/policy.h CHANGED
@@ -7,7 +7,6 @@
7
7
  #define BITCOIN_POLICY_POLICY_H
8
8
 
9
9
  #include <consensus/consensus.h>
10
- #include <policy/feerate.h>
11
10
  #include <script/interpreter.h>
12
11
  #include <script/standard.h>
13
12
 
@@ -18,8 +17,6 @@ class CTxOut;
18
17
 
19
18
  /** Default for -blockmaxweight, which controls the range of block weights the mining code will create **/
20
19
  static const unsigned int DEFAULT_BLOCK_MAX_WEIGHT = MAX_BLOCK_WEIGHT - 4000;
21
- /** Default for -blockmintxfee, which sets the minimum feerate for a transaction in blocks created by mining code **/
22
- static const unsigned int DEFAULT_BLOCK_MIN_TX_FEE = 1000;
23
20
  /** The maximum weight for transactions we're willing to relay/mine */
24
21
  static const unsigned int MAX_STANDARD_TX_WEIGHT = 400000;
25
22
  /** The minimum non-witness size for transactions we're willing to relay/mine (1 segwit input + 1 P2WPKH output = 82 bytes) */
@@ -30,8 +27,6 @@ static const unsigned int MAX_P2SH_SIGOPS = 15;
30
27
  static const unsigned int MAX_STANDARD_TX_SIGOPS_COST = MAX_BLOCK_SIGOPS_COST/5;
31
28
  /** Default for -maxmempool, maximum megabytes of mempool memory usage */
32
29
  static const unsigned int DEFAULT_MAX_MEMPOOL_SIZE = 300;
33
- /** Default for -incrementalrelayfee, which sets the minimum feerate increase for mempool limiting or BIP 125 replacement **/
34
- static const unsigned int DEFAULT_INCREMENTAL_RELAY_FEE = 1000;
35
30
  /** Default for -bytespersigop */
36
31
  static const unsigned int DEFAULT_BYTES_PER_SIGOP = 20;
37
32
  /** Default for -permitbaremultisig */
@@ -46,12 +41,6 @@ static const unsigned int MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE = 80;
46
41
  static const unsigned int MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600;
47
42
  /** The maximum size of a standard ScriptSig */
48
43
  static const unsigned int MAX_STANDARD_SCRIPTSIG_SIZE = 1650;
49
- /** Min feerate for defining dust. Historically this has been based on the
50
- * minRelayTxFee, however changing the dust limit changes which transactions are
51
- * standard and should be done with care and ideally rarely. It makes sense to
52
- * only increase the dust limit after prior releases were already not creating
53
- * outputs below the new threshold */
54
- static const unsigned int DUST_RELAY_TX_FEE = 3000;
55
44
  /**
56
45
  * Standard script verification flags that standard transactions will comply
57
46
  * with. However scripts violating these flags may still be present in valid
@@ -73,7 +62,6 @@ static constexpr unsigned int STANDARD_SCRIPT_VERIFY_FLAGS = MANDATORY_SCRIPT_VE
73
62
  SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_WITNESS_PROGRAM |
74
63
  SCRIPT_VERIFY_WITNESS_PUBKEYTYPE |
75
64
  SCRIPT_VERIFY_CONST_SCRIPTCODE |
76
- SCRIPT_VERIFY_TAPROOT |
77
65
  SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_TAPROOT_VERSION |
78
66
  SCRIPT_VERIFY_DISCOURAGE_OP_SUCCESS |
79
67
  SCRIPT_VERIFY_DISCOURAGE_UPGRADABLE_PUBKEYTYPE;
@@ -85,23 +73,19 @@ static constexpr unsigned int STANDARD_NOT_MANDATORY_VERIFY_FLAGS = STANDARD_SCR
85
73
  static constexpr unsigned int STANDARD_LOCKTIME_VERIFY_FLAGS = LOCKTIME_VERIFY_SEQUENCE |
86
74
  LOCKTIME_MEDIAN_TIME_PAST;
87
75
 
88
- CAmount GetDustThreshold(const CTxOut& txout, const CFeeRate& dustRelayFee);
89
-
90
- bool IsDust(const CTxOut& txout, const CFeeRate& dustRelayFee);
91
-
92
76
  bool IsStandard(const CScript& scriptPubKey, TxoutType& whichType);
93
77
 
94
78
 
95
79
  // Changing the default transaction version requires a two step process: first
96
80
  // adapting relay policy by bumping TX_MAX_STANDARD_VERSION, and then later
97
81
  // allowing the new transaction version in the wallet/RPC.
98
- static constexpr decltype(CTransaction::nVersion) TX_MAX_STANDARD_VERSION{2};
82
+ static constexpr decltype(CTransaction::nVersion) TX_MAX_STANDARD_VERSION{3};
99
83
 
100
84
  /**
101
85
  * Check for standard transaction types
102
86
  * @return True if all outputs (scriptPubKeys) use only standard transaction forms
103
87
  */
104
- bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, const CFeeRate& dust_relay_fee, std::string& reason);
88
+ bool IsStandardTx(const CTransaction& tx, bool permit_bare_multisig, std::string& reason);
105
89
  /**
106
90
  * Check for standard transaction types
107
91
  * @param[in] mapInputs Map of previous transactions that have outputs we're spending
src/policy/rbf.cpp DELETED
@@ -1,176 +0,0 @@
1
- // Copyright (c) 2016-2021 The Bitcoin Core developers
2
- // Distributed under the MIT software license, see the accompanying
3
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
-
5
- #include <policy/rbf.h>
6
-
7
- #include <policy/settings.h>
8
- #include <tinyformat.h>
9
- #include <util/moneystr.h>
10
- #include <util/rbf.h>
11
-
12
- RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool)
13
- {
14
- AssertLockHeld(pool.cs);
15
-
16
- CTxMemPool::setEntries ancestors;
17
-
18
- // First check the transaction itself.
19
- if (SignalsOptInRBF(tx)) {
20
- return RBFTransactionState::REPLACEABLE_BIP125;
21
- }
22
-
23
- // If this transaction is not in our mempool, then we can't be sure
24
- // we will know about all its inputs.
25
- if (!pool.exists(GenTxid::Txid(tx.GetHash()))) {
26
- return RBFTransactionState::UNKNOWN;
27
- }
28
-
29
- // If all the inputs have nSequence >= maxint-1, it still might be
30
- // signaled for RBF if any unconfirmed parents have signaled.
31
- uint64_t noLimit = std::numeric_limits<uint64_t>::max();
32
- std::string dummy;
33
- CTxMemPoolEntry entry = *pool.mapTx.find(tx.GetHash());
34
- pool.CalculateMemPoolAncestors(entry, ancestors, noLimit, noLimit, noLimit, noLimit, dummy, false);
35
-
36
- for (CTxMemPool::txiter it : ancestors) {
37
- if (SignalsOptInRBF(it->GetTx())) {
38
- return RBFTransactionState::REPLACEABLE_BIP125;
39
- }
40
- }
41
- return RBFTransactionState::FINAL;
42
- }
43
-
44
- RBFTransactionState IsRBFOptInEmptyMempool(const CTransaction& tx)
45
- {
46
- // If we don't have a local mempool we can only check the transaction itself.
47
- return SignalsOptInRBF(tx) ? RBFTransactionState::REPLACEABLE_BIP125 : RBFTransactionState::UNKNOWN;
48
- }
49
-
50
- std::optional<std::string> GetEntriesForConflicts(const CTransaction& tx,
51
- CTxMemPool& pool,
52
- const CTxMemPool::setEntries& iters_conflicting,
53
- CTxMemPool::setEntries& all_conflicts)
54
- {
55
- AssertLockHeld(pool.cs);
56
- const uint256 txid = tx.GetHash();
57
- uint64_t nConflictingCount = 0;
58
- for (const auto& mi : iters_conflicting) {
59
- nConflictingCount += mi->GetCountWithDescendants();
60
- // BIP125 Rule #5: don't consider replacing more than MAX_BIP125_REPLACEMENT_CANDIDATES
61
- // entries from the mempool. This potentially overestimates the number of actual
62
- // descendants (i.e. if multiple conflicts share a descendant, it will be counted multiple
63
- // times), but we just want to be conservative to avoid doing too much work.
64
- if (nConflictingCount > MAX_BIP125_REPLACEMENT_CANDIDATES) {
65
- return strprintf("rejecting replacement %s; too many potential replacements (%d > %d)\n",
66
- txid.ToString(),
67
- nConflictingCount,
68
- MAX_BIP125_REPLACEMENT_CANDIDATES);
69
- }
70
- }
71
- // Calculate the set of all transactions that would have to be evicted.
72
- for (CTxMemPool::txiter it : iters_conflicting) {
73
- pool.CalculateDescendants(it, all_conflicts);
74
- }
75
- return std::nullopt;
76
- }
77
-
78
- std::optional<std::string> HasNoNewUnconfirmed(const CTransaction& tx,
79
- const CTxMemPool& pool,
80
- const CTxMemPool::setEntries& iters_conflicting)
81
- {
82
- AssertLockHeld(pool.cs);
83
- std::set<uint256> parents_of_conflicts;
84
- for (const auto& mi : iters_conflicting) {
85
- for (const CTxIn& txin : mi->GetTx().vin) {
86
- parents_of_conflicts.insert(txin.prevout.hash);
87
- }
88
- }
89
-
90
- for (unsigned int j = 0; j < tx.vin.size(); j++) {
91
- // BIP125 Rule #2: We don't want to accept replacements that require low feerate junk to be
92
- // mined first. Ideally we'd keep track of the ancestor feerates and make the decision
93
- // based on that, but for now requiring all new inputs to be confirmed works.
94
- //
95
- // Note that if you relax this to make RBF a little more useful, this may break the
96
- // CalculateMempoolAncestors RBF relaxation which subtracts the conflict count/size from the
97
- // descendant limit.
98
- if (!parents_of_conflicts.count(tx.vin[j].prevout.hash)) {
99
- // Rather than check the UTXO set - potentially expensive - it's cheaper to just check
100
- // if the new input refers to a tx that's in the mempool.
101
- if (pool.exists(GenTxid::Txid(tx.vin[j].prevout.hash))) {
102
- return strprintf("replacement %s adds unconfirmed input, idx %d",
103
- tx.GetHash().ToString(), j);
104
- }
105
- }
106
- }
107
- return std::nullopt;
108
- }
109
-
110
- std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries& ancestors,
111
- const std::set<uint256>& direct_conflicts,
112
- const uint256& txid)
113
- {
114
- for (CTxMemPool::txiter ancestorIt : ancestors) {
115
- const uint256& hashAncestor = ancestorIt->GetTx().GetHash();
116
- if (direct_conflicts.count(hashAncestor)) {
117
- return strprintf("%s spends conflicting transaction %s",
118
- txid.ToString(),
119
- hashAncestor.ToString());
120
- }
121
- }
122
- return std::nullopt;
123
- }
124
-
125
- std::optional<std::string> PaysMoreThanConflicts(const CTxMemPool::setEntries& iters_conflicting,
126
- CFeeRate replacement_feerate,
127
- const uint256& txid)
128
- {
129
- for (const auto& mi : iters_conflicting) {
130
- // Don't allow the replacement to reduce the feerate of the mempool.
131
- //
132
- // We usually don't want to accept replacements with lower feerates than what they replaced
133
- // as that would lower the feerate of the next block. Requiring that the feerate always be
134
- // increased is also an easy-to-reason about way to prevent DoS attacks via replacements.
135
- //
136
- // We only consider the feerates of transactions being directly replaced, not their indirect
137
- // descendants. While that does mean high feerate children are ignored when deciding whether
138
- // or not to replace, we do require the replacement to pay more overall fees too, mitigating
139
- // most cases.
140
- CFeeRate original_feerate(mi->GetModifiedFee(), mi->GetTxSize());
141
- if (replacement_feerate <= original_feerate) {
142
- return strprintf("rejecting replacement %s; new feerate %s <= old feerate %s",
143
- txid.ToString(),
144
- replacement_feerate.ToString(),
145
- original_feerate.ToString());
146
- }
147
- }
148
- return std::nullopt;
149
- }
150
-
151
- std::optional<std::string> PaysForRBF(CAmount original_fees,
152
- CAmount replacement_fees,
153
- size_t replacement_vsize,
154
- CFeeRate relay_fee,
155
- const uint256& txid)
156
- {
157
- // BIP125 Rule #3: The replacement fees must be greater than or equal to fees of the
158
- // transactions it replaces, otherwise the bandwidth used by those conflicting transactions
159
- // would not be paid for.
160
- if (replacement_fees < original_fees) {
161
- return strprintf("rejecting replacement %s, less fees than conflicting txs; %s < %s",
162
- txid.ToString(), FormatMoney(replacement_fees), FormatMoney(original_fees));
163
- }
164
-
165
- // BIP125 Rule #4: The new transaction must pay for its own bandwidth. Otherwise, we have a DoS
166
- // vector where attackers can cause a transaction to be replaced (and relayed) repeatedly by
167
- // increasing the fee by tiny amounts.
168
- CAmount additional_fees = replacement_fees - original_fees;
169
- if (additional_fees < relay_fee.GetFee(replacement_vsize)) {
170
- return strprintf("rejecting replacement %s, not enough additional fees to relay; %s < %s",
171
- txid.ToString(),
172
- FormatMoney(additional_fees),
173
- FormatMoney(relay_fee.GetFee(replacement_vsize)));
174
- }
175
- return std::nullopt;
176
- }
src/policy/rbf.h DELETED
@@ -1,102 +0,0 @@
1
- // Copyright (c) 2016-2021 The Bitcoin Core developers
2
- // Distributed under the MIT software license, see the accompanying
3
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
-
5
- #ifndef BITCOIN_POLICY_RBF_H
6
- #define BITCOIN_POLICY_RBF_H
7
-
8
- #include <primitives/transaction.h>
9
- #include <txmempool.h>
10
- #include <uint256.h>
11
-
12
- #include <optional>
13
- #include <string>
14
-
15
- /** Maximum number of transactions that can be replaced by BIP125 RBF (Rule #5). This includes all
16
- * mempool conflicts and their descendants. */
17
- static constexpr uint32_t MAX_BIP125_REPLACEMENT_CANDIDATES{100};
18
-
19
- /** The rbf state of unconfirmed transactions */
20
- enum class RBFTransactionState {
21
- /** Unconfirmed tx that does not signal rbf and is not in the mempool */
22
- UNKNOWN,
23
- /** Either this tx or a mempool ancestor signals rbf */
24
- REPLACEABLE_BIP125,
25
- /** Neither this tx nor a mempool ancestor signals rbf */
26
- FINAL,
27
- };
28
-
29
- /**
30
- * Determine whether an unconfirmed transaction is signaling opt-in to RBF
31
- * according to BIP 125
32
- * This involves checking sequence numbers of the transaction, as well
33
- * as the sequence numbers of all in-mempool ancestors.
34
- *
35
- * @param tx The unconfirmed transaction
36
- * @param pool The mempool, which may contain the tx
37
- *
38
- * @return The rbf state
39
- */
40
- RBFTransactionState IsRBFOptIn(const CTransaction& tx, const CTxMemPool& pool) EXCLUSIVE_LOCKS_REQUIRED(pool.cs);
41
- RBFTransactionState IsRBFOptInEmptyMempool(const CTransaction& tx);
42
-
43
- /** Get all descendants of iters_conflicting. Also enforce BIP125 Rule #5, "The number of original
44
- * transactions to be replaced and their descendant transactions which will be evicted from the
45
- * mempool must not exceed a total of 100 transactions." Quit as early as possible. There cannot be
46
- * more than MAX_BIP125_REPLACEMENT_CANDIDATES potential entries.
47
- * @param[in] iters_conflicting The set of iterators to mempool entries.
48
- * @param[out] all_conflicts Populated with all the mempool entries that would be replaced,
49
- * which includes descendants of iters_conflicting. Not cleared at
50
- * the start; any existing mempool entries will remain in the set.
51
- * @returns an error message if Rule #5 is broken, otherwise a std::nullopt.
52
- */
53
- std::optional<std::string> GetEntriesForConflicts(const CTransaction& tx, CTxMemPool& pool,
54
- const CTxMemPool::setEntries& iters_conflicting,
55
- CTxMemPool::setEntries& all_conflicts)
56
- EXCLUSIVE_LOCKS_REQUIRED(pool.cs);
57
-
58
- /** BIP125 Rule #2: "The replacement transaction may only include an unconfirmed input if that input
59
- * was included in one of the original transactions."
60
- * @returns error message if Rule #2 is broken, otherwise std::nullopt. */
61
- std::optional<std::string> HasNoNewUnconfirmed(const CTransaction& tx, const CTxMemPool& pool,
62
- const CTxMemPool::setEntries& iters_conflicting)
63
- EXCLUSIVE_LOCKS_REQUIRED(pool.cs);
64
-
65
- /** Check the intersection between two sets of transactions (a set of mempool entries and a set of
66
- * txids) to make sure they are disjoint.
67
- * @param[in] ancestors Set of mempool entries corresponding to ancestors of the
68
- * replacement transactions.
69
- * @param[in] direct_conflicts Set of txids corresponding to the mempool conflicts
70
- * (candidates to be replaced).
71
- * @param[in] txid Transaction ID, included in the error message if violation occurs.
72
- * @returns error message if the sets intersect, std::nullopt if they are disjoint.
73
- */
74
- std::optional<std::string> EntriesAndTxidsDisjoint(const CTxMemPool::setEntries& ancestors,
75
- const std::set<uint256>& direct_conflicts,
76
- const uint256& txid);
77
-
78
- /** Check that the feerate of the replacement transaction(s) is higher than the feerate of each
79
- * of the transactions in iters_conflicting.
80
- * @param[in] iters_conflicting The set of mempool entries.
81
- * @returns error message if fees insufficient, otherwise std::nullopt.
82
- */
83
- std::optional<std::string> PaysMoreThanConflicts(const CTxMemPool::setEntries& iters_conflicting,
84
- CFeeRate replacement_feerate, const uint256& txid);
85
-
86
- /** Enforce BIP125 Rule #3 "The replacement transaction pays an absolute fee of at least the sum
87
- * paid by the original transactions." Enforce BIP125 Rule #4 "The replacement transaction must also
88
- * pay for its own bandwidth at or above the rate set by the node's minimum relay fee setting."
89
- * @param[in] original_fees Total modified fees of original transaction(s).
90
- * @param[in] replacement_fees Total modified fees of replacement transaction(s).
91
- * @param[in] replacement_vsize Total virtual size of replacement transaction(s).
92
- * @param[in] relay_fee The node's minimum feerate for transaction relay.
93
- * @param[in] txid Transaction ID, included in the error message if violation occurs.
94
- * @returns error string if fees are insufficient, otherwise std::nullopt.
95
- */
96
- std::optional<std::string> PaysForRBF(CAmount original_fees,
97
- CAmount replacement_fees,
98
- size_t replacement_vsize,
99
- CFeeRate relay_fee,
100
- const uint256& txid);
101
-
102
- #endif // BITCOIN_POLICY_RBF_H
src/policy/settings.cpp CHANGED
@@ -5,10 +5,7 @@
5
5
 
6
6
  #include <policy/settings.h>
7
7
 
8
- #include <policy/feerate.h>
9
8
  #include <policy/policy.h>
10
9
 
11
10
  bool fIsBareMultisigStd = DEFAULT_PERMIT_BAREMULTISIG;
12
- CFeeRate incrementalRelayFee = CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE);
13
- CFeeRate dustRelayFee = CFeeRate(DUST_RELAY_TX_FEE);
14
11
  unsigned int nBytesPerSigOp = DEFAULT_BYTES_PER_SIGOP;
src/policy/settings.h CHANGED
@@ -8,18 +8,15 @@
8
8
 
9
9
  #include <policy/policy.h>
10
10
 
11
- class CFeeRate;
12
11
  class CTransaction;
13
12
 
14
13
  // Policy settings which are configurable at runtime.
15
- extern CFeeRate incrementalRelayFee;
16
- extern CFeeRate dustRelayFee;
17
14
  extern unsigned int nBytesPerSigOp;
18
15
  extern bool fIsBareMultisigStd;
19
16
 
20
17
  static inline bool IsStandardTx(const CTransaction& tx, std::string& reason)
21
18
  {
22
- return IsStandardTx(tx, ::fIsBareMultisigStd, ::dustRelayFee, reason);
19
+ return IsStandardTx(tx, ::fIsBareMultisigStd, reason);
23
20
  }
24
21
 
25
22
  static inline int64_t GetVirtualTransactionSize(int64_t weight, int64_t sigop_cost)
src/pow.cpp CHANGED
@@ -10,63 +10,53 @@
10
10
  #include <primitives/block.h>
11
11
  #include <uint256.h>
12
12
 
13
- unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params& params)
13
+ #include <bignum.h>
14
+ #include <chainparams.h>
15
+ #include <kernel.h>
16
+
17
+ unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake, const Consensus::Params& params)
14
18
  {
15
- assert(pindexLast != nullptr);
16
- unsigned int nProofOfWorkLimit = UintToArith256(params.powLimit).GetCompact();
17
-
18
- // Only change once per difficulty adjustment interval
19
- if ((pindexLast->nHeight+1) % params.DifficultyAdjustmentInterval() != 0)
20
- {
21
- if (params.fPowAllowMinDifficultyBlocks)
22
- {
23
- // Special difficulty rule for testnet:
24
- // If the new block's timestamp is more than 2* 10 minutes
25
- // then allow mining of a min-difficulty block.
26
- if (pblock->GetBlockTime() > pindexLast->GetBlockTime() + params.nPowTargetSpacing*2)
27
- return nProofOfWorkLimit;
28
- else
29
- {
30
- // Return the last non-special-min-difficulty-rules-block
31
- const CBlockIndex* pindex = pindexLast;
32
- while (pindex->pprev && pindex->nHeight % params.DifficultyAdjustmentInterval() != 0 && pindex->nBits == nProofOfWorkLimit)
33
- pindex = pindex->pprev;
34
- return pindex->nBits;
19
+ if (pindexLast == nullptr)
20
+ return UintToArith256(params.powLimit).GetCompact(); // genesis block
21
+
22
+ const CBlockIndex* pindexPrev = GetLastBlockIndex(pindexLast, fProofOfStake);
23
+ if (pindexPrev->pprev == nullptr)
24
+ return UintToArith256(params.bnInitialHashTarget).GetCompact(); // first block
25
+ const CBlockIndex* pindexPrevPrev = GetLastBlockIndex(pindexPrev->pprev, fProofOfStake);
26
+ if (pindexPrevPrev->pprev == nullptr)
27
+ return UintToArith256(params.bnInitialHashTarget).GetCompact(); // second block
28
+
29
+ int64_t nActualSpacing = pindexPrev->GetBlockTime() - pindexPrevPrev->GetBlockTime();
30
+
31
+ // rfc20
32
+ int64_t nHypotheticalSpacing = pindexLast->GetBlockTime() - pindexPrev->GetBlockTime();
33
+ if (!fProofOfStake && IsProtocolV12(pindexPrev) && (nHypotheticalSpacing > nActualSpacing))
34
+ nActualSpacing = nHypotheticalSpacing;
35
+
36
+ // peercoin: target change every block
37
+ // peercoin: retarget with exponential moving toward target spacing
38
+ CBigNum bnNew;
39
+ bnNew.SetCompact(pindexPrev->nBits);
40
+ if (Params().NetworkIDString() != CBaseChainParams::REGTEST) {
41
+ int64_t nTargetSpacing;
42
+
43
+ if (fProofOfStake) {
44
+ nTargetSpacing = params.nStakeTargetSpacing;
45
+ } else {
46
+ if (IsProtocolV09(pindexLast->nTime)) {
47
+ nTargetSpacing = params.nStakeTargetSpacing * 6;
48
+ } else {
49
+ nTargetSpacing = std::min(params.nTargetSpacingWorkMax, params.nStakeTargetSpacing * (1 + pindexLast->nHeight - pindexPrev->nHeight));
35
50
  }
36
51
  }
37
- return pindexLast->nBits;
38
- }
39
-
40
- // Go back by what we want to be 14 days worth of blocks
41
- int nHeightFirst = pindexLast->nHeight - (params.DifficultyAdjustmentInterval()-1);
42
- assert(nHeightFirst >= 0);
43
- const CBlockIndex* pindexFirst = pindexLast->GetAncestor(nHeightFirst);
44
- assert(pindexFirst);
45
52
 
46
- return CalculateNextWorkRequired(pindexLast, pindexFirst->GetBlockTime(), params);
47
- }
53
+ int64_t nInterval = params.nTargetTimespan / nTargetSpacing;
54
+ bnNew *= ((nInterval - 1) * nTargetSpacing + nActualSpacing + nActualSpacing);
55
+ bnNew /= ((nInterval + 1) * nTargetSpacing);
56
+ }
48
57
 
49
- unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params& params)
50
- {
51
- if (params.fPowNoRetargeting)
52
- return pindexLast->nBits;
53
-
54
- // Limit adjustment step
55
- int64_t nActualTimespan = pindexLast->GetBlockTime() - nFirstBlockTime;
56
- if (nActualTimespan < params.nPowTargetTimespan/4)
57
- nActualTimespan = params.nPowTargetTimespan/4;
58
- if (nActualTimespan > params.nPowTargetTimespan*4)
59
- nActualTimespan = params.nPowTargetTimespan*4;
60
-
61
- // Retarget
62
- const arith_uint256 bnPowLimit = UintToArith256(params.powLimit);
63
- arith_uint256 bnNew;
64
- bnNew.SetCompact(pindexLast->nBits);
65
- bnNew *= nActualTimespan;
66
- bnNew /= params.nPowTargetTimespan;
67
-
68
- if (bnNew > bnPowLimit)
69
- bnNew = bnPowLimit;
58
+ if (bnNew > CBigNum(params.powLimit))
59
+ bnNew = CBigNum(params.powLimit);
70
60
 
71
61
  return bnNew.GetCompact();
72
62
  }
src/pow.h CHANGED
@@ -14,8 +14,7 @@ class CBlockHeader;
14
14
  class CBlockIndex;
15
15
  class uint256;
16
16
 
17
- unsigned int GetNextWorkRequired(const CBlockIndex* pindexLast, const CBlockHeader *pblock, const Consensus::Params&);
18
- unsigned int CalculateNextWorkRequired(const CBlockIndex* pindexLast, int64_t nFirstBlockTime, const Consensus::Params&);
17
+ unsigned int GetNextTargetRequired(const CBlockIndex* pindexLast, bool fProofOfStake, const Consensus::Params& params);
19
18
 
20
19
  /** Check whether a block hash satisfies the proof-of-work requirement specified by nBits */
21
20
  bool CheckProofOfWork(uint256 hash, unsigned int nBits, const Consensus::Params&);
src/primitives/block.cpp CHANGED
@@ -10,19 +10,21 @@
10
10
 
11
11
  uint256 CBlockHeader::GetHash() const
12
12
  {
13
- return SerializeHash(*this);
13
+ CBlockHeader tmp(*this);
14
+ tmp.nFlags = 0;
15
+ return SerializeHash(tmp);
14
16
  }
15
17
 
16
18
  std::string CBlock::ToString() const
17
19
  {
18
20
  std::stringstream s;
19
- s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, vtx=%u)\n",
21
+ s << strprintf("CBlock(hash=%s, ver=0x%08x, hashPrevBlock=%s, hashMerkleRoot=%s, nTime=%u, nBits=%08x, nNonce=%u, nFlags=%08x, vtx=%u)\n",
20
22
  GetHash().ToString(),
21
23
  nVersion,
22
24
  hashPrevBlock.ToString(),
23
25
  hashMerkleRoot.ToString(),
24
26
  nTime, nBits, nNonce,
25
- vtx.size());
27
+ nFlags, vtx.size());
26
28
  for (const auto& tx : vtx) {
27
29
  s << " " << tx->ToString() << "\n";
28
30
  }
src/primitives/block.h CHANGED
@@ -28,21 +28,34 @@ public:
28
28
  uint32_t nBits;
29
29
  uint32_t nNonce;
30
30
 
31
+ // peercoin: A copy from CBlockIndex.nFlags from other clients. We need this information because we are using headers-first syncronization.
32
+ uint32_t nFlags;
33
+ // peercoin: Used in CheckProofOfStake().
34
+ static const int32_t NORMAL_SERIALIZE_SIZE=80;
35
+ static const int32_t CURRENT_VERSION=4;
36
+
31
37
  CBlockHeader()
32
38
  {
33
39
  SetNull();
34
40
  }
35
41
 
36
- SERIALIZE_METHODS(CBlockHeader, obj) { READWRITE(obj.nVersion, obj.hashPrevBlock, obj.hashMerkleRoot, obj.nTime, obj.nBits, obj.nNonce); }
42
+ SERIALIZE_METHODS(CBlockHeader, obj)
43
+ {
44
+ READWRITE(obj.nVersion, obj.hashPrevBlock, obj.hashMerkleRoot, obj.nTime, obj.nBits, obj.nNonce);
45
+ // peercoin: do not serialize nFlags when computing hash
46
+ if (!(s.GetType() & SER_GETHASH) && s.GetType() & SER_POSMARKER)
47
+ READWRITE(obj.nFlags);
48
+ }
37
49
 
38
50
  void SetNull()
39
51
  {
40
- nVersion = 0;
52
+ nVersion = CURRENT_VERSION;
41
53
  hashPrevBlock.SetNull();
42
54
  hashMerkleRoot.SetNull();
43
55
  nTime = 0;
44
56
  nBits = 0;
45
57
  nNonce = 0;
58
+ nFlags = 0;
46
59
  }
47
60
 
48
61
  bool IsNull() const
@@ -65,6 +78,9 @@ public:
65
78
  // network and disk
66
79
  std::vector<CTransactionRef> vtx;
67
80
 
81
+ // peercoin: block signature - signed by coin base txout[0]'s owner
82
+ std::vector<unsigned char> vchBlockSig;
83
+
68
84
  // memory only
69
85
  mutable bool fChecked;
70
86
 
@@ -83,6 +99,7 @@ public:
83
99
  {
84
100
  READWRITEAS(CBlockHeader, obj);
85
101
  READWRITE(obj.vtx);
102
+ READWRITE(obj.vchBlockSig);
86
103
  }
87
104
 
88
105
  void SetNull()
@@ -90,6 +107,7 @@ public:
90
107
  CBlockHeader::SetNull();
91
108
  vtx.clear();
92
109
  fChecked = false;
110
+ vchBlockSig.clear();
93
111
  }
94
112
 
95
113
  CBlockHeader GetBlockHeader() const
@@ -101,9 +119,37 @@ public:
101
119
  block.nTime = nTime;
102
120
  block.nBits = nBits;
103
121
  block.nNonce = nNonce;
122
+ block.nFlags = nFlags;
104
123
  return block;
105
124
  }
106
125
 
126
+ // peercoin: two types of block: proof-of-work or proof-of-stake
127
+ bool IsProofOfStake() const
128
+ {
129
+ return (vtx.size() > 1 && vtx[1]->IsCoinStake());
130
+ }
131
+
132
+ bool IsProofOfWork() const
133
+ {
134
+ return !IsProofOfStake();
135
+ }
136
+
137
+ std::pair<COutPoint, unsigned int> GetProofOfStake() const
138
+ {
139
+ return IsProofOfStake() ? std::make_pair(vtx[1]->vin[0].prevout, vtx[1]->nTime) : std::make_pair(COutPoint(), (unsigned int)0);
140
+ }
141
+
142
+ // peercoin: get max transaction timestamp
143
+ int64_t GetMaxTransactionTime() const
144
+ {
145
+ int64_t maxTransactionTime = 0;
146
+ for (const auto& tx : vtx)
147
+ maxTransactionTime = std::max(maxTransactionTime, (int64_t)tx->nTime);
148
+ return maxTransactionTime;
149
+ }
150
+
151
+ unsigned int GetStakeEntropyBit() const; // peercoin: entropy bit for stake modifier if chosen by modifier
152
+
107
153
  std::string ToString() const;
108
154
  };
109
155
 
src/primitives/transaction.cpp CHANGED
@@ -11,6 +11,7 @@
11
11
  #include <util/strencodings.h>
12
12
 
13
13
  #include <assert.h>
14
+ #include <timedata.h>
14
15
 
15
16
  std::string COutPoint::ToString() const
16
17
  {
@@ -54,11 +55,11 @@ CTxOut::CTxOut(const CAmount& nValueIn, CScript scriptPubKeyIn)
54
55
 
55
56
  std::string CTxOut::ToString() const
56
57
  {
57
- return strprintf("CTxOut(nValue=%d.%08d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30));
58
+ return strprintf("CTxOut(nValue=%d.%06d, scriptPubKey=%s)", nValue / COIN, nValue % COIN, HexStr(scriptPubKey).substr(0, 30));
58
59
  }
59
60
 
60
- CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nLockTime(0) {}
61
- CMutableTransaction::CMutableTransaction(const CTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime) {}
61
+ CMutableTransaction::CMutableTransaction() : nVersion(CTransaction::CURRENT_VERSION), nTime(GetAdjustedTime()), nLockTime(0) {}
62
+ CMutableTransaction::CMutableTransaction(const CTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nTime(tx.nTime), nLockTime(tx.nLockTime) {}
62
63
 
63
64
  uint256 CMutableTransaction::GetHash() const
64
65
  {
@@ -78,8 +79,8 @@ uint256 CTransaction::ComputeWitnessHash() const
78
79
  return SerializeHash(*this, SER_GETHASH, 0);
79
80
  }
80
81
 
81
- CTransaction::CTransaction(const CMutableTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
82
- CTransaction::CTransaction(CMutableTransaction&& tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
82
+ CTransaction::CTransaction(const CMutableTransaction& tx) : vin(tx.vin), vout(tx.vout), nVersion(tx.nVersion), nTime(tx.nTime), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
83
+ CTransaction::CTransaction(CMutableTransaction&& tx) : vin(std::move(tx.vin)), vout(std::move(tx.vout)), nVersion(tx.nVersion), nTime(tx.nTime), nLockTime(tx.nLockTime), hash{ComputeHash()}, m_witness_hash{ComputeWitnessHash()} {}
83
84
 
84
85
  CAmount CTransaction::GetValueOut() const
85
86
  {
@@ -101,8 +102,10 @@ unsigned int CTransaction::GetTotalSize() const
101
102
  std::string CTransaction::ToString() const
102
103
  {
103
104
  std::string str;
104
- str += strprintf("CTransaction(hash=%s, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n",
105
+ str += IsCoinBase()? "Coinbase" : (IsCoinStake()? "Coinstake" : "CTransaction");
106
+ str += strprintf("(hash=%s, nTime=%d, ver=%d, vin.size=%u, vout.size=%u, nLockTime=%u)\n",
105
107
  GetHash().ToString().substr(0,10),
108
+ nTime,
106
109
  nVersion,
107
110
  vin.size(),
108
111
  vout.size(),
src/primitives/transaction.h CHANGED
@@ -12,6 +12,7 @@
12
12
  #include <serialize.h>
13
13
  #include <uint256.h>
14
14
 
15
+ #include <version.h>
15
16
  #include <tuple>
16
17
 
17
18
  /**
@@ -171,6 +172,17 @@ public:
171
172
  return (nValue == -1);
172
173
  }
173
174
 
175
+ void SetEmpty()
176
+ {
177
+ nValue = 0;
178
+ scriptPubKey.clear();
179
+ }
180
+
181
+ bool IsEmpty() const
182
+ {
183
+ return (nValue == 0 && scriptPubKey.empty());
184
+ }
185
+
174
186
  friend bool operator==(const CTxOut& a, const CTxOut& b)
175
187
  {
176
188
  return (a.nValue == b.nValue &&
@@ -209,6 +221,11 @@ inline void UnserializeTransaction(TxType& tx, Stream& s) {
209
221
  const bool fAllowWitness = !(s.GetVersion() & SERIALIZE_TRANSACTION_NO_WITNESS);
210
222
 
211
223
  s >> tx.nVersion;
224
+ if (tx.nVersion < 3)
225
+ s >> tx.nTime;
226
+ else
227
+ tx.nTime = 0;
228
+
212
229
  unsigned char flags = 0;
213
230
  tx.vin.clear();
214
231
  tx.vout.clear();
@@ -248,6 +265,8 @@ inline void SerializeTransaction(const TxType& tx, Stream& s) {
248
265
  const bool fAllowWitness = !(s.GetVersion() & SERIALIZE_TRANSACTION_NO_WITNESS);
249
266
 
250
267
  s << tx.nVersion;
268
+ if (tx.nVersion<3)
269
+ s << tx.nTime;
251
270
  unsigned char flags = 0;
252
271
  // Consistency check
253
272
  if (fAllowWitness) {
@@ -272,7 +291,6 @@ inline void SerializeTransaction(const TxType& tx, Stream& s) {
272
291
  s << tx.nLockTime;
273
292
  }
274
293
 
275
-
276
294
  /** The basic transaction that is broadcasted on the network and contained in
277
295
  * blocks. A transaction can contain multiple inputs and outputs.
278
296
  */
@@ -280,7 +298,7 @@ class CTransaction
280
298
  {
281
299
  public:
282
300
  // Default transaction version.
283
- static const int32_t CURRENT_VERSION=2;
301
+ static const int32_t CURRENT_VERSION=3;
284
302
 
285
303
  // The local variables are made const to prevent unintended modification
286
304
  // without updating the cached hash value. However, CTransaction is not
@@ -290,6 +308,7 @@ public:
290
308
  const std::vector<CTxIn> vin;
291
309
  const std::vector<CTxOut> vout;
292
310
  const int32_t nVersion;
311
+ const uint32_t nTime;
293
312
  const uint32_t nLockTime;
294
313
 
295
314
  private:
@@ -334,7 +353,13 @@ public:
334
353
 
335
354
  bool IsCoinBase() const
336
355
  {
337
- return (vin.size() == 1 && vin[0].prevout.IsNull());
356
+ return (vin.size() == 1 && vin[0].prevout.IsNull() && vout.size() >= 1);
357
+ }
358
+
359
+ bool IsCoinStake() const
360
+ {
361
+ // peercoin: the coin stake transaction is marked with the first output empty
362
+ return (vin.size() > 0 && (!vin[0].prevout.IsNull()) && vout.size() >= 2 && vout[0].IsEmpty());
338
363
  }
339
364
 
340
365
  friend bool operator==(const CTransaction& a, const CTransaction& b)
@@ -366,6 +391,7 @@ struct CMutableTransaction
366
391
  std::vector<CTxIn> vin;
367
392
  std::vector<CTxOut> vout;
368
393
  int32_t nVersion;
394
+ uint32_t nTime;
369
395
  uint32_t nLockTime;
370
396
 
371
397
  CMutableTransaction();
src/protocol.cpp CHANGED
@@ -181,6 +181,7 @@ const std::vector<std::string> &getAllNetMessageTypes()
181
181
  return allNetMessageTypesVec;
182
182
  }
183
183
 
184
+ const unsigned int POW_HEADER_COOLING = 70;
184
185
  /**
185
186
  * Convert a service flag (NODE_*) to a human readable string.
186
187
  * It supports unknown service flags which will be returned as "UNKNOWN[...]".
src/protocol.h CHANGED
@@ -273,7 +273,7 @@ enum ServiceFlags : uint64_t {
273
273
  // Nothing
274
274
  NODE_NONE = 0,
275
275
  // NODE_NETWORK means that the node is capable of serving the complete block chain. It is currently
276
- // set by all Bitcoin Core non pruned nodes, and is unset by SPV clients or other light clients.
276
+ // set by all Bitcoin Core nodes, and is unset by SPV clients or other light clients.
277
277
  NODE_NETWORK = (1 << 0),
278
278
  // NODE_BLOOM means the node is capable and willing to handle bloom-filtered connections.
279
279
  // Bitcoin Core nodes used to support this by default, without advertising this bit,
@@ -511,4 +511,7 @@ public:
511
511
  /** Convert a TX/WITNESS_TX/WTX CInv to a GenTxid. */
512
512
  GenTxid ToGenTxid(const CInv& inv);
513
513
 
514
+ /** peercoin: How much temperature a PoW header will remove */
515
+ extern const unsigned int POW_HEADER_COOLING;
516
+
514
517
  #endif // BITCOIN_PROTOCOL_H
src/psbt.h CHANGED
@@ -7,7 +7,6 @@
7
7
 
8
8
  #include <attributes.h>
9
9
  #include <node/transaction.h>
10
- #include <policy/feerate.h>
11
10
  #include <primitives/transaction.h>
12
11
  #include <pubkey.h>
13
12
  #include <script/keyorigin.h>
src/rest.cpp CHANGED
@@ -33,7 +33,6 @@
33
33
  #include <univalue.h>
34
34
 
35
35
  using node::GetTransaction;
36
- using node::IsBlockPruned;
37
36
  using node::NodeContext;
38
37
  using node::ReadBlockFromDisk;
39
38
 
@@ -296,8 +295,6 @@ static bool rest_block(const std::any& context,
296
295
  return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
297
296
  }
298
297
 
299
- if (IsBlockPruned(pblockindex))
300
- return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not available (pruned data)");
301
298
 
302
299
  if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus()))
303
300
  return RESTERR(req, HTTP_NOT_FOUND, hashStr + " not found");
src/rpc/blockchain.cpp CHANGED
@@ -14,7 +14,6 @@
14
14
  #include <consensus/validation.h>
15
15
  #include <core_io.h>
16
16
  #include <deploymentinfo.h>
17
- #include <deploymentstatus.h>
18
17
  #include <fs.h>
19
18
  #include <hash.h>
20
19
  #include <index/blockfilterindex.h>
@@ -26,10 +25,7 @@
26
25
  #include <node/coinstats.h>
27
26
  #include <node/context.h>
28
27
  #include <node/utxo_snapshot.h>
29
- #include <policy/feerate.h>
30
- #include <policy/fees.h>
31
28
  #include <policy/policy.h>
32
- #include <policy/rbf.h>
33
29
  #include <primitives/transaction.h>
34
30
  #include <rpc/server.h>
35
31
  #include <rpc/server_util.h>
@@ -45,13 +41,15 @@
45
41
  #include <util/translation.h>
46
42
  #include <validation.h>
47
43
  #include <validationinterface.h>
48
- #include <versionbits.h>
49
44
  #include <warnings.h>
50
45
 
51
46
  #include <stdint.h>
52
47
 
53
48
  #include <univalue.h>
54
49
 
50
+ #include <node/miner.h>
51
+ #include <kernel.h>
52
+ #include <validation.h>
55
53
  #include <condition_variable>
56
54
  #include <memory>
57
55
  #include <mutex>
@@ -60,7 +58,6 @@ using node::BlockManager;
60
58
  using node::CCoinsStats;
61
59
  using node::CoinStatsHashType;
62
60
  using node::GetUTXOStats;
63
- using node::IsBlockPruned;
64
61
  using node::NodeContext;
65
62
  using node::ReadBlockFromDisk;
66
63
  using node::SnapshotMetadata;
@@ -78,21 +75,28 @@ static CUpdatedBlock latestblock GUARDED_BY(cs_blockchange);
78
75
 
79
76
  /* Calculate the difficulty for a given block index.
80
77
  */
81
- double GetDifficulty(const CBlockIndex* blockindex)
78
+ double GetDifficulty(const CBlockIndex* blockindex, const CBlockIndex* tip)
82
79
  {
83
- CHECK_NONFATAL(blockindex);
80
+ LOCK(cs_main);
81
+
82
+ // minimum difficulty = 1.0.
83
+ if (blockindex == nullptr) {
84
+ if (tip == nullptr)
85
+ return 1.0;
86
+ else
87
+ blockindex = GetLastBlockIndex(tip, false);
88
+ }
84
89
 
85
90
  int nShift = (blockindex->nBits >> 24) & 0xff;
91
+
86
92
  double dDiff =
87
93
  (double)0x0000ffff / (double)(blockindex->nBits & 0x00ffffff);
88
94
 
89
- while (nShift < 29)
90
- {
95
+ while (nShift < 29) {
91
96
  dDiff *= 256.0;
92
97
  nShift++;
93
98
  }
94
- while (nShift > 29)
95
- {
99
+ while (nShift > 29) {
96
100
  dDiff /= 256.0;
97
101
  nShift--;
98
102
  }
@@ -155,8 +159,8 @@ UniValue blockheaderToJSON(const CBlockIndex* tip, const CBlockIndex* blockindex
155
159
  result.pushKV("mediantime", (int64_t)blockindex->GetMedianTimePast());
156
160
  result.pushKV("nonce", (uint64_t)blockindex->nNonce);
157
161
  result.pushKV("bits", strprintf("%08x", blockindex->nBits));
158
- result.pushKV("difficulty", GetDifficulty(blockindex));
159
- result.pushKV("chainwork", blockindex->nChainWork.GetHex());
162
+ result.pushKV("difficulty", GetDifficulty(blockindex, tip));
163
+ result.pushKV("chainwork", blockindex->nChainTrust.GetHex());
160
164
  result.pushKV("nTx", (uint64_t)blockindex->nTx);
161
165
 
162
166
  if (blockindex->pprev)
@@ -173,6 +177,13 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
173
177
  result.pushKV("strippedsize", (int)::GetSerializeSize(block, PROTOCOL_VERSION | SERIALIZE_TRANSACTION_NO_WITNESS));
174
178
  result.pushKV("size", (int)::GetSerializeSize(block, PROTOCOL_VERSION));
175
179
  result.pushKV("weight", (int)::GetBlockWeight(block));
180
+ result.pushKV("mint", ValueFromAmount(blockindex->nMint));
181
+ result.pushKV("flags", strprintf("%s%s", blockindex->IsProofOfStake()? "proof-of-stake" : "proof-of-work", blockindex->GeneratedStakeModifier()? " stake-modifier": ""));
182
+ result.pushKV("proofhash", blockindex->IsProofOfStake()? blockindex->hashProofOfStake.GetHex() : blockindex->GetBlockHash().GetHex());
183
+ result.pushKV("entropybit", (int)blockindex->GetStakeEntropyBit());
184
+ result.pushKV("modifier", strprintf("%016llx", blockindex->nStakeModifier));
185
+ result.pushKV("modifierchecksum", strprintf("%08x", blockindex->nStakeModifierChecksum));
186
+ result.pushKV("blocksignature", HexStr(block.vchBlockSig));
176
187
  UniValue txs(UniValue::VARR);
177
188
 
178
189
  switch (verbosity) {
@@ -185,7 +196,7 @@ UniValue blockToJSON(const CBlock& block, const CBlockIndex* tip, const CBlockIn
185
196
  case TxVerbosity::SHOW_DETAILS:
186
197
  case TxVerbosity::SHOW_DETAILS_AND_PREVOUT:
187
198
  CBlockUndo blockUndo;
188
- const bool have_undo{WITH_LOCK(::cs_main, return !IsBlockPruned(blockindex) && UndoReadFromDisk(blockUndo, blockindex))};
199
+ const bool have_undo{WITH_LOCK(::cs_main, return UndoReadFromDisk(blockUndo, blockindex))};
189
200
 
190
201
  for (size_t i = 0; i < block.vtx.size(); ++i) {
191
202
  const CTransactionRef& tx = block.vtx.at(i);
@@ -409,10 +420,14 @@ static RPCHelpMan syncwithvalidationinterfacequeue()
409
420
  static RPCHelpMan getdifficulty()
410
421
  {
411
422
  return RPCHelpMan{"getdifficulty",
412
- "\nReturns the proof-of-work difficulty as a multiple of the minimum difficulty.\n",
423
+ "\nReturns the difficulty as a multiple of the minimum difficulty.\n",
413
424
  {},
414
425
  RPCResult{
415
- RPCResult::Type::NUM, "", "the proof-of-work difficulty as a multiple of the minimum difficulty."},
426
+ RPCResult::Type::OBJ, "", "",
427
+ {
428
+ {RPCResult::Type::NUM, "proof-of-work", "the difficulty as a multiple of the minimum difficulty of proof of work blocks"},
429
+ {RPCResult::Type::NUM, "proof-of-stake", "the difficulty as a multiple of the minimum difficulty of proof of stake blocks"},
430
+ }},
416
431
  RPCExamples{
417
432
  HelpExampleCli("getdifficulty", "")
418
433
  + HelpExampleRpc("getdifficulty", "")
@@ -421,7 +436,11 @@ static RPCHelpMan getdifficulty()
421
436
  {
422
437
  ChainstateManager& chainman = EnsureAnyChainman(request.context);
423
438
  LOCK(cs_main);
424
- return GetDifficulty(chainman.ActiveChain().Tip());
439
+ UniValue obj(UniValue::VOBJ);
440
+ obj.pushKV("proof-of-work", GetDifficulty(NULL, chainman.ActiveChain().Tip()));
441
+ obj.pushKV("proof-of-stake", GetDifficulty(GetLastBlockIndex(chainman.ActiveChain().Tip(), true), chainman.ActiveChain().Tip()));
442
+ obj.pushKV("search-interval", (int)nLastCoinStakeSearchInterval);
443
+ return obj;
425
444
  },
426
445
  };
427
446
  }
@@ -432,7 +451,7 @@ static std::vector<RPCResult> MempoolEntryDescription() { return {
432
451
  RPCResult{RPCResult::Type::STR_AMOUNT, "fee", /*optional=*/true,
433
452
  "transaction fee, denominated in " + CURRENCY_UNIT + " (DEPRECATED, returned only if config option -deprecatedrpc=fees is passed)"},
434
453
  RPCResult{RPCResult::Type::STR_AMOUNT, "modifiedfee", /*optional=*/true,
435
- "transaction fee with fee deltas used for mining priority, denominated in " + CURRENCY_UNIT +
454
+ "transaction fee with fee deltas used for mining priority, denominated in " + CURRENCY_ATOM +
436
455
  " (DEPRECATED, returned only if config option -deprecatedrpc=fees is passed)"},
437
456
  RPCResult{RPCResult::Type::NUM_TIME, "time", "local time transaction entered pool in seconds since 1 Jan 1970 GMT"},
438
457
  RPCResult{RPCResult::Type::NUM, "height", "block height when transaction entered pool"},
@@ -458,7 +477,6 @@ static std::vector<RPCResult> MempoolEntryDescription() { return {
458
477
  {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "parent transaction id"}}},
459
478
  RPCResult{RPCResult::Type::ARR, "spentby", "unconfirmed transactions spending outputs from this transaction",
460
479
  {RPCResult{RPCResult::Type::STR_HEX, "transactionid", "child transaction id"}}},
461
- RPCResult{RPCResult::Type::BOOL, "bip125-replaceable", "Whether this transaction could be replaced due to BIP125 (replace-by-fee)"},
462
480
  RPCResult{RPCResult::Type::BOOL, "unbroadcast", "Whether this transaction is currently unbroadcast (initial broadcast not yet acknowledged by any peers)"},
463
481
  };}
464
482
 
@@ -519,17 +537,6 @@ static void entryToJSON(const CTxMemPool& pool, UniValue& info, const CTxMemPool
519
537
  }
520
538
 
521
539
  info.pushKV("spentby", spent);
522
-
523
- // Add opt-in RBF status
524
- bool rbfStatus = false;
525
- RBFTransactionState rbfState = IsRBFOptIn(tx, pool);
526
- if (rbfState == RBFTransactionState::UNKNOWN) {
527
- throw JSONRPCError(RPC_MISC_ERROR, "Transaction is not in mempool");
528
- } else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125) {
529
- rbfStatus = true;
530
- }
531
-
532
- info.pushKV("bip125-replaceable", rbfStatus);
533
540
  info.pushKV("unbroadcast", pool.IsUnbroadcastTx(tx.GetHash()));
534
541
  }
535
542
 
@@ -934,9 +941,6 @@ static CBlock GetBlockChecked(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS_RE
934
941
  {
935
942
  AssertLockHeld(::cs_main);
936
943
  CBlock block;
937
- if (IsBlockPruned(pblockindex)) {
938
- throw JSONRPCError(RPC_MISC_ERROR, "Block not available (pruned data)");
939
- }
940
944
 
941
945
  if (!ReadBlockFromDisk(block, pblockindex, Params().GetConsensus())) {
942
946
  // Block not found on disk. This could be because we have the block
@@ -952,9 +956,6 @@ static CBlockUndo GetUndoChecked(const CBlockIndex* pblockindex) EXCLUSIVE_LOCKS
952
956
  {
953
957
  AssertLockHeld(::cs_main);
954
958
  CBlockUndo blockUndo;
955
- if (IsBlockPruned(pblockindex)) {
956
- throw JSONRPCError(RPC_MISC_ERROR, "Undo data not available (pruned data)");
957
- }
958
959
 
959
960
  if (!UndoReadFromDisk(blockUndo, pblockindex)) {
960
961
  throw JSONRPCError(RPC_MISC_ERROR, "Can't read undo data from disk");
@@ -969,7 +970,7 @@ static RPCHelpMan getblock()
969
970
  "\nIf verbosity is 0, returns a string that is serialized, hex-encoded data for block 'hash'.\n"
970
971
  "If verbosity is 1, returns an Object with information about block <hash>.\n"
971
972
  "If verbosity is 2, returns an Object with information about block <hash> and information about each transaction.\n"
972
- "If verbosity is 3, returns an Object with information about block <hash> and information about each transaction, including prevout information for inputs (only for unpruned blocks in the current best chain).\n",
973
+ "If verbosity is 3, returns an Object with information about block <hash> and information about each transaction, including prevout information for inputs.\n",
973
974
  {
974
975
  {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The block hash"},
975
976
  {"verbosity|verbose", RPCArg::Type::NUM, RPCArg::Default{1}, "0 for hex-encoded data, 1 for a JSON object, 2 for JSON object with transaction data, and 3 for JSON object with transaction data including prevout information for inputs"},
@@ -1101,65 +1102,6 @@ static RPCHelpMan getblock()
1101
1102
  };
1102
1103
  }
1103
1104
 
1104
- static RPCHelpMan pruneblockchain()
1105
- {
1106
- return RPCHelpMan{"pruneblockchain", "",
1107
- {
1108
- {"height", RPCArg::Type::NUM, RPCArg::Optional::NO, "The block height to prune up to. May be set to a discrete height, or to a " + UNIX_EPOCH_TIME + "\n"
1109
- " to prune blocks whose block time is at least 2 hours older than the provided timestamp."},
1110
- },
1111
- RPCResult{
1112
- RPCResult::Type::NUM, "", "Height of the last block pruned"},
1113
- RPCExamples{
1114
- HelpExampleCli("pruneblockchain", "1000")
1115
- + HelpExampleRpc("pruneblockchain", "1000")
1116
- },
1117
- [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1118
- {
1119
- if (!node::fPruneMode)
1120
- throw JSONRPCError(RPC_MISC_ERROR, "Cannot prune blocks because node is not in prune mode.");
1121
-
1122
- ChainstateManager& chainman = EnsureAnyChainman(request.context);
1123
- LOCK(cs_main);
1124
- CChainState& active_chainstate = chainman.ActiveChainstate();
1125
- CChain& active_chain = active_chainstate.m_chain;
1126
-
1127
- int heightParam = request.params[0].get_int();
1128
- if (heightParam < 0)
1129
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Negative block height.");
1130
-
1131
- // Height value more than a billion is too high to be a block height, and
1132
- // too low to be a block time (corresponds to timestamp from Sep 2001).
1133
- if (heightParam > 1000000000) {
1134
- // Add a 2 hour buffer to include blocks which might have had old timestamps
1135
- CBlockIndex* pindex = active_chain.FindEarliestAtLeast(heightParam - TIMESTAMP_WINDOW, 0);
1136
- if (!pindex) {
1137
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Could not find block with at least the specified timestamp.");
1138
- }
1139
- heightParam = pindex->nHeight;
1140
- }
1141
-
1142
- unsigned int height = (unsigned int) heightParam;
1143
- unsigned int chainHeight = (unsigned int) active_chain.Height();
1144
- if (chainHeight < Params().PruneAfterHeight())
1145
- throw JSONRPCError(RPC_MISC_ERROR, "Blockchain is too short for pruning.");
1146
- else if (height > chainHeight)
1147
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Blockchain is shorter than the attempted prune height.");
1148
- else if (height > chainHeight - MIN_BLOCKS_TO_KEEP) {
1149
- LogPrint(BCLog::RPC, "Attempt to prune blocks close to the tip. Retaining the minimum number of blocks.\n");
1150
- height = chainHeight - MIN_BLOCKS_TO_KEEP;
1151
- }
1152
-
1153
- PruneBlockFilesManual(active_chainstate, height);
1154
- const CBlockIndex* block = active_chain.Tip();
1155
- CHECK_NONFATAL(block);
1156
- while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
1157
- block = block->pprev;
1158
- }
1159
- return uint64_t(block->nHeight);
1160
- },
1161
- };
1162
- }
1163
1105
 
1164
1106
  CoinStatsHashType ParseHashType(const std::string& hash_type_input)
1165
1107
  {
@@ -1337,7 +1279,7 @@ static RPCHelpMan gettxout()
1337
1279
  {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
1338
1280
  {RPCResult::Type::STR_HEX, "hex", ""},
1339
1281
  {RPCResult::Type::STR, "type", "The type, eg pubkeyhash"},
1340
- {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
1282
+ {RPCResult::Type::STR, "address", /*optional=*/true, "The Peercoin address (only if a well-defined address exists)"},
1341
1283
  }},
1342
1284
  {RPCResult::Type::BOOL, "coinbase", "Coinbase or not"},
1343
1285
  }},
@@ -1430,96 +1372,37 @@ static RPCHelpMan verifychain()
1430
1372
  };
1431
1373
  }
1432
1374
 
1433
- static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const Consensus::Params& params, Consensus::BuriedDeployment dep)
1375
+ /** Implementation of IsSuperMajority with better feedback */
1376
+ static UniValue SoftForkMajorityDesc(int version, const CBlockIndex* pindex, const Consensus::Params& consensusParams)
1434
1377
  {
1435
- // For buried deployments.
1436
-
1437
- if (!DeploymentEnabled(params, dep)) return;
1438
-
1439
1378
  UniValue rv(UniValue::VOBJ);
1440
- rv.pushKV("type", "buried");
1441
- // getdeploymentinfo reports the softfork as active from when the chain height is
1442
- // one below the activation height
1443
- rv.pushKV("active", DeploymentActiveAfter(blockindex, params, dep));
1444
- rv.pushKV("height", params.DeploymentHeight(dep));
1445
- softforks.pushKV(DeploymentName(dep), rv);
1379
+ bool activated = false;
1380
+ switch(version)
1381
+ {
1382
+ case 2:
1383
+ activated = pindex->nHeight >= consensusParams.BIP34Height;
1384
+ break;
1385
+ case 3:
1386
+ activated = IsBTC16BIPsEnabled(pindex->nTime);
1387
+ break;
1388
+ case 4:
1389
+ activated = IsProtocolV06(pindex);
1390
+ break;
1391
+ case 12:
1392
+ activated = IsProtocolV12(pindex);
1393
+ break;
1394
+ }
1395
+ rv.pushKV("status", activated);
1396
+ return rv;
1446
1397
  }
1447
1398
 
1448
- static void SoftForkDescPushBack(const CBlockIndex* blockindex, UniValue& softforks, const Consensus::Params& consensusParams, Consensus::DeploymentPos id)
1399
+ static UniValue SoftForkDesc(const std::string &name, int version, const CBlockIndex* pindex, const Consensus::Params& consensusParams)
1449
1400
  {
1450
- // For BIP9 deployments.
1451
-
1452
- if (!DeploymentEnabled(consensusParams, id)) return;
1453
- if (blockindex == nullptr) return;
1454
-
1455
- auto get_state_name = [](const ThresholdState state) -> std::string {
1456
- switch (state) {
1457
- case ThresholdState::DEFINED: return "defined";
1458
- case ThresholdState::STARTED: return "started";
1459
- case ThresholdState::LOCKED_IN: return "locked_in";
1460
- case ThresholdState::ACTIVE: return "active";
1461
- case ThresholdState::FAILED: return "failed";
1462
- }
1463
- return "invalid";
1464
- };
1465
-
1466
- UniValue bip9(UniValue::VOBJ);
1467
-
1468
- const ThresholdState next_state = g_versionbitscache.State(blockindex, consensusParams, id);
1469
- const ThresholdState current_state = g_versionbitscache.State(blockindex->pprev, consensusParams, id);
1470
-
1471
- const bool has_signal = (ThresholdState::STARTED == current_state || ThresholdState::LOCKED_IN == current_state);
1472
-
1473
- // BIP9 parameters
1474
- if (has_signal) {
1475
- bip9.pushKV("bit", consensusParams.vDeployments[id].bit);
1476
- }
1477
- bip9.pushKV("start_time", consensusParams.vDeployments[id].nStartTime);
1478
- bip9.pushKV("timeout", consensusParams.vDeployments[id].nTimeout);
1479
- bip9.pushKV("min_activation_height", consensusParams.vDeployments[id].min_activation_height);
1480
-
1481
- // BIP9 status
1482
- bip9.pushKV("status", get_state_name(current_state));
1483
- bip9.pushKV("since", g_versionbitscache.StateSinceHeight(blockindex->pprev, consensusParams, id));
1484
- bip9.pushKV("status_next", get_state_name(next_state));
1485
-
1486
- // BIP9 signalling status, if applicable
1487
- if (has_signal) {
1488
- UniValue statsUV(UniValue::VOBJ);
1489
- std::vector<bool> signals;
1490
- BIP9Stats statsStruct = g_versionbitscache.Statistics(blockindex, consensusParams, id, &signals);
1491
- statsUV.pushKV("period", statsStruct.period);
1492
- statsUV.pushKV("elapsed", statsStruct.elapsed);
1493
- statsUV.pushKV("count", statsStruct.count);
1494
- if (ThresholdState::LOCKED_IN != current_state) {
1495
- statsUV.pushKV("threshold", statsStruct.threshold);
1496
- statsUV.pushKV("possible", statsStruct.possible);
1497
- }
1498
- bip9.pushKV("statistics", statsUV);
1499
-
1500
- std::string sig;
1501
- sig.reserve(signals.size());
1502
- for (const bool s : signals) {
1503
- sig.push_back(s ? '#' : '-');
1504
- }
1505
- bip9.pushKV("signalling", sig);
1506
- }
1507
-
1508
1401
  UniValue rv(UniValue::VOBJ);
1509
- rv.pushKV("type", "bip9");
1510
- if (ThresholdState::ACTIVE == next_state) {
1511
- rv.pushKV("height", g_versionbitscache.StateSinceHeight(blockindex, consensusParams, id));
1512
- }
1513
- rv.pushKV("active", ThresholdState::ACTIVE == next_state);
1514
- rv.pushKV("bip9", bip9);
1515
-
1516
- softforks.pushKV(DeploymentName(id), rv);
1517
- }
1518
-
1519
- namespace {
1520
- /* TODO: when -deprecatedrpc=softforks is removed, drop these */
1521
- UniValue DeploymentInfo(const CBlockIndex* tip, const Consensus::Params& consensusParams);
1522
- extern const std::vector<RPCResult> RPCHelpForDeployment;
1402
+ rv.pushKV("id", name);
1403
+ rv.pushKV("version", version);
1404
+ rv.pushKV("active", SoftForkMajorityDesc(version, pindex, consensusParams));
1405
+ return rv;
1523
1406
  }
1524
1407
 
1525
1408
  // used by rest.cpp:rest_chaininfo, so cannot be static
@@ -1543,16 +1426,6 @@ RPCHelpMan getblockchaininfo()
1543
1426
  {RPCResult::Type::BOOL, "initialblockdownload", "(debug information) estimate of whether this node is in Initial Block Download mode"},
1544
1427
  {RPCResult::Type::STR_HEX, "chainwork", "total amount of work in active chain, in hexadecimal"},
1545
1428
  {RPCResult::Type::NUM, "size_on_disk", "the estimated size of the block and undo files on disk"},
1546
- {RPCResult::Type::BOOL, "pruned", "if the blocks are subject to pruning"},
1547
- {RPCResult::Type::NUM, "pruneheight", /*optional=*/true, "lowest-height complete block stored (only present if pruning is enabled)"},
1548
- {RPCResult::Type::BOOL, "automatic_pruning", /*optional=*/true, "whether automatic pruning is enabled (only present if pruning is enabled)"},
1549
- {RPCResult::Type::NUM, "prune_target_size", /*optional=*/true, "the target size used by pruning (only present if automatic pruning is enabled)"},
1550
- {RPCResult::Type::OBJ_DYN, "softforks", "(DEPRECATED, returned only if config option -deprecatedrpc=softforks is passed) status of softforks",
1551
- {
1552
- {RPCResult::Type::OBJ, "xxxx", "name of the softfork",
1553
- RPCHelpForDeployment
1554
- },
1555
- }},
1556
1429
  {RPCResult::Type::STR, "warnings", "any network and blockchain warnings"},
1557
1430
  }},
1558
1431
  RPCExamples{
@@ -1561,9 +1434,8 @@ RPCHelpMan getblockchaininfo()
1561
1434
  },
1562
1435
  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1563
1436
  {
1564
- const ArgsManager& args{EnsureAnyArgsman(request.context)};
1565
- ChainstateManager& chainman = EnsureAnyChainman(request.context);
1566
1437
  LOCK(cs_main);
1438
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
1567
1439
  CChainState& active_chainstate = chainman.ActiveChainstate();
1568
1440
 
1569
1441
  const CBlockIndex* tip = active_chainstate.m_chain.Tip();
@@ -1574,35 +1446,22 @@ RPCHelpMan getblockchaininfo()
1574
1446
  obj.pushKV("blocks", height);
1575
1447
  obj.pushKV("headers", pindexBestHeader ? pindexBestHeader->nHeight : -1);
1576
1448
  obj.pushKV("bestblockhash", tip->GetBlockHash().GetHex());
1577
- obj.pushKV("difficulty", (double)GetDifficulty(tip));
1449
+ obj.pushKV("difficulty", (double)GetDifficulty(tip, tip));
1578
1450
  obj.pushKV("time", (int64_t)tip->nTime);
1579
1451
  obj.pushKV("mediantime", (int64_t)tip->GetMedianTimePast());
1580
1452
  obj.pushKV("verificationprogress", GuessVerificationProgress(Params().TxData(), tip));
1581
1453
  obj.pushKV("initialblockdownload", active_chainstate.IsInitialBlockDownload());
1582
- obj.pushKV("chainwork", tip->nChainWork.GetHex());
1454
+ obj.pushKV("chainwork", tip->nChainTrust.GetHex());
1583
1455
  obj.pushKV("size_on_disk", chainman.m_blockman.CalculateCurrentUsage());
1584
- obj.pushKV("pruned", node::fPruneMode);
1585
- if (node::fPruneMode) {
1586
- const CBlockIndex* block = tip;
1587
- CHECK_NONFATAL(block);
1588
- while (block->pprev && (block->pprev->nStatus & BLOCK_HAVE_DATA)) {
1589
- block = block->pprev;
1590
- }
1591
1456
 
1592
- obj.pushKV("pruneheight", block->nHeight);
1457
+ UniValue softforks(UniValue::VARR);
1458
+ softforks.push_back(SoftForkDesc("bip34", 2, tip, Params().GetConsensus()));
1459
+ softforks.push_back(SoftForkDesc("bip66", 3, tip, Params().GetConsensus()));
1460
+ softforks.push_back(SoftForkDesc("bip65", 4, tip, Params().GetConsensus()));
1461
+ softforks.push_back(SoftForkDesc("v12", 12, tip, Params().GetConsensus()));
1593
1462
 
1594
- // if 0, execution bypasses the whole if block.
1595
- bool automatic_pruning{args.GetIntArg("-prune", 0) != 1};
1596
- obj.pushKV("automatic_pruning", automatic_pruning);
1597
- if (automatic_pruning) {
1598
- obj.pushKV("prune_target_size", node::nPruneTarget);
1599
- }
1600
- }
1601
-
1602
- if (IsDeprecatedRPCEnabled("softforks")) {
1603
- const Consensus::Params& consensusParams = Params().GetConsensus();
1604
- obj.pushKV("softforks", DeploymentInfo(tip, consensusParams));
1605
- }
1463
+ // BIP9SoftForkDescPushBack(tip, softforks, "taproot", consensusParams, Consensus::DEPLOYMENT_TAPROOT);
1464
+ obj.pushKV("softforks", softforks);
1606
1465
 
1607
1466
  obj.pushKV("warnings", GetWarnings(false).original);
1608
1467
  return obj;
@@ -1610,92 +1469,6 @@ RPCHelpMan getblockchaininfo()
1610
1469
  };
1611
1470
  }
1612
1471
 
1613
- namespace {
1614
- const std::vector<RPCResult> RPCHelpForDeployment{
1615
- {RPCResult::Type::STR, "type", "one of \"buried\", \"bip9\""},
1616
- {RPCResult::Type::NUM, "height", /*optional=*/true, "height of the first block which the rules are or will be enforced (only for \"buried\" type, or \"bip9\" type with \"active\" status)"},
1617
- {RPCResult::Type::BOOL, "active", "true if the rules are enforced for the mempool and the next block"},
1618
- {RPCResult::Type::OBJ, "bip9", /*optional=*/true, "status of bip9 softforks (only for \"bip9\" type)",
1619
- {
1620
- {RPCResult::Type::NUM, "bit", /*optional=*/true, "the bit (0-28) in the block version field used to signal this softfork (only for \"started\" and \"locked_in\" status)"},
1621
- {RPCResult::Type::NUM_TIME, "start_time", "the minimum median time past of a block at which the bit gains its meaning"},
1622
- {RPCResult::Type::NUM_TIME, "timeout", "the median time past of a block at which the deployment is considered failed if not yet locked in"},
1623
- {RPCResult::Type::NUM, "min_activation_height", "minimum height of blocks for which the rules may be enforced"},
1624
- {RPCResult::Type::STR, "status", "status of deployment at specified block (one of \"defined\", \"started\", \"locked_in\", \"active\", \"failed\")"},
1625
- {RPCResult::Type::NUM, "since", "height of the first block to which the status applies"},
1626
- {RPCResult::Type::STR, "status_next", "status of deployment at the next block"},
1627
- {RPCResult::Type::OBJ, "statistics", /*optional=*/true, "numeric statistics about signalling for a softfork (only for \"started\" and \"locked_in\" status)",
1628
- {
1629
- {RPCResult::Type::NUM, "period", "the length in blocks of the signalling period"},
1630
- {RPCResult::Type::NUM, "threshold", /*optional=*/true, "the number of blocks with the version bit set required to activate the feature (only for \"started\" status)"},
1631
- {RPCResult::Type::NUM, "elapsed", "the number of blocks elapsed since the beginning of the current period"},
1632
- {RPCResult::Type::NUM, "count", "the number of blocks with the version bit set in the current period"},
1633
- {RPCResult::Type::BOOL, "possible", /*optional=*/true, "returns false if there are not enough blocks left in this period to pass activation threshold (only for \"started\" status)"},
1634
- }},
1635
- {RPCResult::Type::STR, "signalling", "indicates blocks that signalled with a # and blocks that did not with a -"},
1636
- }},
1637
- };
1638
-
1639
- UniValue DeploymentInfo(const CBlockIndex* blockindex, const Consensus::Params& consensusParams)
1640
- {
1641
- UniValue softforks(UniValue::VOBJ);
1642
- SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_HEIGHTINCB);
1643
- SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_DERSIG);
1644
- SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_CLTV);
1645
- SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_CSV);
1646
- SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_SEGWIT);
1647
- SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_TESTDUMMY);
1648
- SoftForkDescPushBack(blockindex, softforks, consensusParams, Consensus::DEPLOYMENT_TAPROOT);
1649
- return softforks;
1650
- }
1651
- } // anon namespace
1652
-
1653
- static RPCHelpMan getdeploymentinfo()
1654
- {
1655
- return RPCHelpMan{"getdeploymentinfo",
1656
- "Returns an object containing various state info regarding deployments of consensus changes.",
1657
- {
1658
- {"blockhash", RPCArg::Type::STR_HEX, RPCArg::Default{"hash of current chain tip"}, "The block hash at which to query deployment state"},
1659
- },
1660
- RPCResult{
1661
- RPCResult::Type::OBJ, "", "", {
1662
- {RPCResult::Type::STR, "hash", "requested block hash (or tip)"},
1663
- {RPCResult::Type::NUM, "height", "requested block height (or tip)"},
1664
- {RPCResult::Type::OBJ, "deployments", "", {
1665
- {RPCResult::Type::OBJ, "xxxx", "name of the deployment", RPCHelpForDeployment}
1666
- }},
1667
- }
1668
- },
1669
- RPCExamples{ HelpExampleCli("getdeploymentinfo", "") + HelpExampleRpc("getdeploymentinfo", "") },
1670
- [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1671
- {
1672
- const ChainstateManager& chainman = EnsureAnyChainman(request.context);
1673
- LOCK(cs_main);
1674
- const CChainState& active_chainstate = chainman.ActiveChainstate();
1675
-
1676
- const CBlockIndex* blockindex;
1677
- if (request.params[0].isNull()) {
1678
- blockindex = active_chainstate.m_chain.Tip();
1679
- CHECK_NONFATAL(blockindex);
1680
- } else {
1681
- const uint256 hash(ParseHashV(request.params[0], "blockhash"));
1682
- blockindex = chainman.m_blockman.LookupBlockIndex(hash);
1683
- if (!blockindex) {
1684
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found");
1685
- }
1686
- }
1687
-
1688
- const Consensus::Params& consensusParams = Params().GetConsensus();
1689
-
1690
- UniValue deploymentinfo(UniValue::VOBJ);
1691
- deploymentinfo.pushKV("hash", blockindex->GetBlockHash().ToString());
1692
- deploymentinfo.pushKV("height", blockindex->nHeight);
1693
- deploymentinfo.pushKV("deployments", DeploymentInfo(blockindex, consensusParams));
1694
- return deploymentinfo;
1695
- },
1696
- };
1697
- }
1698
-
1699
1472
  /** Comparison function for sorting the getchaintips heads. */
1700
1473
  struct CompareBlocksByHeight
1701
1474
  {
@@ -1821,8 +1594,6 @@ UniValue MempoolInfoToJSON(const CTxMemPool& pool)
1821
1594
  ret.pushKV("total_fee", ValueFromAmount(pool.GetTotalFee()));
1822
1595
  size_t maxmempool = gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000;
1823
1596
  ret.pushKV("maxmempool", (int64_t) maxmempool);
1824
- ret.pushKV("mempoolminfee", ValueFromAmount(std::max(pool.GetMinFee(maxmempool), ::minRelayTxFee).GetFeePerK()));
1825
- ret.pushKV("minrelaytxfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
1826
1597
  ret.pushKV("unbroadcastcount", uint64_t{pool.GetUnbroadcastTxs().size()});
1827
1598
  return ret;
1828
1599
  }
@@ -1841,7 +1612,6 @@ static RPCHelpMan getmempoolinfo()
1841
1612
  {RPCResult::Type::NUM, "usage", "Total memory usage for the mempool"},
1842
1613
  {RPCResult::Type::STR_AMOUNT, "total_fee", "Total fees for the mempool in " + CURRENCY_UNIT + ", ignoring modified fees through prioritisetransaction"},
1843
1614
  {RPCResult::Type::NUM, "maxmempool", "Maximum memory usage for the mempool"},
1844
- {RPCResult::Type::STR_AMOUNT, "mempoolminfee", "Minimum fee rate in " + CURRENCY_UNIT + "/kvB for tx to be accepted. Is the maximum of minrelaytxfee and minimum mempool fee"},
1845
1615
  {RPCResult::Type::STR_AMOUNT, "minrelaytxfee", "Current minimum relay fee for transactions"},
1846
1616
  {RPCResult::Type::NUM, "unbroadcastcount", "Current number of transactions that haven't passed initial broadcast yet"}
1847
1617
  }},
@@ -2197,7 +1967,7 @@ static RPCHelpMan getblockstats()
2197
1967
  const bool do_medianfee = do_all || stats.count("medianfee") != 0;
2198
1968
  const bool do_feerate_percentiles = do_all || stats.count("feerate_percentiles") != 0;
2199
1969
  const bool loop_inputs = do_all || do_medianfee || do_feerate_percentiles ||
2200
- SetHasKeys(stats, "utxo_size_inc", "totalfee", "avgfee", "avgfeerate", "minfee", "maxfee", "minfeerate", "maxfeerate");
1970
+ SetHasKeys(stats, "utxo_size_inc", "totalfee", "avgfee", "avgfeerate", "minfee", "minfeerate", "maxfeerate");
2201
1971
  const bool loop_outputs = do_all || loop_inputs || stats.count("total_out");
2202
1972
  const bool do_calculate_size = do_mediantxsize ||
2203
1973
  SetHasKeys(stats, "total_size", "avgtxsize", "mintxsize", "maxtxsize", "swtotal_size");
@@ -2312,7 +2082,6 @@ static RPCHelpMan getblockstats()
2312
2082
  ret_all.pushKV("feerate_percentiles", feerates_res);
2313
2083
  ret_all.pushKV("height", (int64_t)pindex->nHeight);
2314
2084
  ret_all.pushKV("ins", inputs);
2315
- ret_all.pushKV("maxfee", maxfee);
2316
2085
  ret_all.pushKV("maxfeerate", maxfeerate);
2317
2086
  ret_all.pushKV("maxtxsize", maxtxsize);
2318
2087
  ret_all.pushKV("medianfee", CalculateTruncatedMedian(fee_array));
@@ -2322,7 +2091,7 @@ static RPCHelpMan getblockstats()
2322
2091
  ret_all.pushKV("minfeerate", (minfeerate == MAX_MONEY) ? 0 : minfeerate);
2323
2092
  ret_all.pushKV("mintxsize", mintxsize == MAX_BLOCK_SERIALIZED_SIZE ? 0 : mintxsize);
2324
2093
  ret_all.pushKV("outs", outputs);
2325
- ret_all.pushKV("subsidy", GetBlockSubsidy(pindex->nHeight, Params().GetConsensus()));
2094
+ ret_all.pushKV("subsidy", GetProofOfWorkReward(pindex->nBits, pindex->nTime));
2326
2095
  ret_all.pushKV("swtotal_size", swtotal_size);
2327
2096
  ret_all.pushKV("swtotal_weight", swtotal_weight);
2328
2097
  ret_all.pushKV("swtxs", swtxs);
@@ -2842,7 +2611,6 @@ static const CRPCCommand commands[] =
2842
2611
  { "blockchain", &getblockheader, },
2843
2612
  { "blockchain", &getchaintips, },
2844
2613
  { "blockchain", &getdifficulty, },
2845
- { "blockchain", &getdeploymentinfo, },
2846
2614
  { "blockchain", &getmempoolancestors, },
2847
2615
  { "blockchain", &getmempooldescendants, },
2848
2616
  { "blockchain", &getmempoolentry, },
@@ -2850,10 +2618,8 @@ static const CRPCCommand commands[] =
2850
2618
  { "blockchain", &getrawmempool, },
2851
2619
  { "blockchain", &gettxout, },
2852
2620
  { "blockchain", &gettxoutsetinfo, },
2853
- { "blockchain", &pruneblockchain, },
2854
2621
  { "blockchain", &savemempool, },
2855
2622
  { "blockchain", &verifychain, },
2856
-
2857
2623
  { "blockchain", &preciousblock, },
2858
2624
  { "blockchain", &scantxoutset, },
2859
2625
  { "blockchain", &getblockfilter, },
src/rpc/blockchain.h CHANGED
@@ -34,7 +34,7 @@ static constexpr int NUM_GETBLOCKSTATS_PERCENTILES = 5;
34
34
  * @return A floating point number that is a multiple of the main net minimum
35
35
  * difficulty (4295032833 hashes).
36
36
  */
37
- double GetDifficulty(const CBlockIndex* blockindex);
37
+ double GetDifficulty(const CBlockIndex* blockindex, const CBlockIndex* tip);
38
38
 
39
39
  /** Callback for when block tip changed. */
40
40
  void RPCNotifyBlockChange(const CBlockIndex*);
src/rpc/client.cpp CHANGED
@@ -70,6 +70,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
70
70
  { "listtransactions", 2, "skip" },
71
71
  { "listtransactions", 3, "include_watchonly" },
72
72
  { "walletpassphrase", 1, "timeout" },
73
+ { "walletpassphrase", 2, "mintonly" },
73
74
  { "getblocktemplate", 0, "template_request" },
74
75
  { "listsinceblock", 1, "target_confirmations" },
75
76
  { "listsinceblock", 2, "include_watchonly" },
@@ -102,7 +103,7 @@ static const CRPCConvertParam vRPCConvertParams[] =
102
103
  { "createrawtransaction", 0, "inputs" },
103
104
  { "createrawtransaction", 1, "outputs" },
104
105
  { "createrawtransaction", 2, "locktime" },
105
- { "createrawtransaction", 3, "replaceable" },
106
+ { "createrawtransaction", 3, "timestamp" },
106
107
  { "decoderawtransaction", 1, "iswitness" },
107
108
  { "signrawtransactionwithkey", 1, "privkeys" },
108
109
  { "signrawtransactionwithkey", 2, "prevtxs" },
@@ -116,15 +117,16 @@ static const CRPCConvertParam vRPCConvertParams[] =
116
117
  { "walletcreatefundedpsbt", 0, "inputs" },
117
118
  { "walletcreatefundedpsbt", 1, "outputs" },
118
119
  { "walletcreatefundedpsbt", 2, "locktime" },
119
- { "walletcreatefundedpsbt", 3, "options" },
120
- { "walletcreatefundedpsbt", 4, "bip32derivs" },
120
+ { "walletcreatefundedpsbt", 3, "timestamp" },
121
+ { "walletcreatefundedpsbt", 4, "options" },
122
+ { "walletcreatefundedpsbt", 5, "bip32derivs" },
121
123
  { "walletprocesspsbt", 1, "sign" },
122
124
  { "walletprocesspsbt", 3, "bip32derivs" },
123
125
  { "walletprocesspsbt", 4, "finalize" },
124
126
  { "createpsbt", 0, "inputs" },
125
127
  { "createpsbt", 1, "outputs" },
126
128
  { "createpsbt", 2, "locktime" },
127
- { "createpsbt", 3, "replaceable" },
129
+ { "createpsbt", 3, "timestamp" },
128
130
  { "combinepsbt", 0, "txs"},
129
131
  { "joinpsbts", 0, "txs"},
130
132
  { "finalizepsbt", 1, "extract"},
@@ -154,22 +156,16 @@ static const CRPCConvertParam vRPCConvertParams[] =
154
156
  { "verifychain", 1, "nblocks" },
155
157
  { "getblockstats", 0, "hash_or_height" },
156
158
  { "getblockstats", 1, "stats" },
157
- { "pruneblockchain", 0, "height" },
158
159
  { "keypoolrefill", 0, "newsize" },
159
160
  { "getrawmempool", 0, "verbose" },
160
161
  { "getrawmempool", 1, "mempool_sequence" },
161
162
  { "estimatesmartfee", 0, "conf_target" },
162
- { "estimaterawfee", 0, "conf_target" },
163
- { "estimaterawfee", 1, "threshold" },
164
- { "prioritisetransaction", 1, "dummy" },
165
- { "prioritisetransaction", 2, "fee_delta" },
166
163
  { "setban", 2, "bantime" },
167
164
  { "setban", 3, "absolute" },
168
165
  { "setnetworkactive", 0, "state" },
169
166
  { "setwalletflag", 1, "value" },
170
167
  { "getmempoolancestors", 1, "verbose" },
171
168
  { "getmempooldescendants", 1, "verbose" },
172
- { "bumpfee", 1, "options" },
173
169
  { "psbtbumpfee", 1, "options" },
174
170
  { "logging", 0, "include" },
175
171
  { "logging", 1, "exclude" },
@@ -201,6 +197,16 @@ static const CRPCConvertParam vRPCConvertParams[] =
201
197
  { "addpeeraddress", 1, "port"},
202
198
  { "addpeeraddress", 2, "tried"},
203
199
  { "stop", 0, "wait" },
200
+ // peercoin:
201
+ { "importcoinstake", 1, "timestamp" },
202
+ { "listminting", 0, "count" },
203
+ { "reservebalance", 0, "reserve" },
204
+ { "reservebalance", 1, "amount" },
205
+ { "sendalert", 2, "minver"},
206
+ { "sendalert", 3, "maxver"},
207
+ { "sendalert", 4, "priority"},
208
+ { "sendalert", 5, "id"},
209
+ { "sendalert", 6, "cancelupto"},
204
210
  };
205
211
  // clang-format on
206
212
 
src/rpc/mining.cpp CHANGED
@@ -11,12 +11,11 @@
11
11
  #include <consensus/validation.h>
12
12
  #include <core_io.h>
13
13
  #include <deploymentinfo.h>
14
- #include <deploymentstatus.h>
15
14
  #include <key_io.h>
15
+ #include <interfaces/wallet.h>
16
16
  #include <net.h>
17
17
  #include <node/context.h>
18
18
  #include <node/miner.h>
19
- #include <policy/fees.h>
20
19
  #include <pow.h>
21
20
  #include <rpc/blockchain.h>
22
21
  #include <rpc/mining.h>
@@ -29,7 +28,6 @@
29
28
  #include <shutdown.h>
30
29
  #include <txmempool.h>
31
30
  #include <univalue.h>
32
- #include <util/fees.h>
33
31
  #include <util/strencodings.h>
34
32
  #include <util/string.h>
35
33
  #include <util/system.h>
@@ -38,6 +36,12 @@
38
36
  #include <validationinterface.h>
39
37
  #include <warnings.h>
40
38
 
39
+ #include <wallet/rpc/util.h>
40
+ #include <wallet/rpc/wallet.h>
41
+ #include <wallet/wallet.h>
42
+
43
+ #include <kernel.h>
44
+
41
45
  #include <memory>
42
46
  #include <stdint.h>
43
47
 
@@ -47,6 +51,9 @@ using node::IncrementExtraNonce;
47
51
  using node::NodeContext;
48
52
  using node::RegenerateCommitments;
49
53
  using node::UpdateTime;
54
+ using interfaces::WalletLoader;
55
+
56
+ using wallet::GetWalletForJSONRPCRequest;
50
57
 
51
58
  /**
52
59
  * Return average network hashes per second based on the last 'lookup' blocks,
@@ -63,9 +70,10 @@ static UniValue GetNetworkHashPS(int lookup, int height, const CChain& active_ch
63
70
  if (pb == nullptr || !pb->nHeight)
64
71
  return 0;
65
72
 
73
+ //ppcTODO - redo this to fit peercoin
66
74
  // If lookup is -1, then use blocks since last difficulty change.
67
- if (lookup <= 0)
68
- lookup = pb->nHeight % Params().GetConsensus().DifficultyAdjustmentInterval() + 1;
75
+ // if (lookup <= 0)
76
+ // lookup = pb->nHeight % Params().GetConsensus().DifficultyAdjustmentInterval() + 1;
69
77
 
70
78
  // If lookup is larger than chain, then set it to chain length.
71
79
  if (lookup > pb->nHeight)
@@ -85,7 +93,7 @@ static UniValue GetNetworkHashPS(int lookup, int height, const CChain& active_ch
85
93
  if (minTime == maxTime)
86
94
  return 0;
87
95
 
88
- arith_uint256 workDiff = pb->nChainWork - pb0->nChainWork;
96
+ arith_uint256 workDiff = pb->nChainTrust - pb0->nChainTrust;
89
97
  int64_t timeDiff = maxTime - minTime;
90
98
 
91
99
  return workDiff.getdouble() / timeDiff;
@@ -116,6 +124,47 @@ static RPCHelpMan getnetworkhashps()
116
124
  };
117
125
  }
118
126
 
127
+ // peercoin: get network Gh/s estimate
128
+ static RPCHelpMan getnetworkghps()
129
+ {
130
+ return RPCHelpMan{"getnetworkghps",
131
+ "\nReturns a recent Ghash/second network mining estimate.\n",
132
+ {
133
+ },
134
+ RPCResult{
135
+ RPCResult::Type::NUM, "", "Ghashes per second estimated"},
136
+ RPCExamples{
137
+ HelpExampleCli("getnetworkghps", "")
138
+ + HelpExampleRpc("getnetworkghps", "")
139
+ },
140
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
141
+ {
142
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
143
+ LOCK(cs_main);
144
+
145
+ int64_t nTargetSpacingWorkMin = 30;
146
+ int64_t nTargetSpacingWork = nTargetSpacingWorkMin;
147
+ int64_t nInterval = 72;
148
+ CBlockIndex* pindex = chainman.ActiveChain().Genesis();
149
+ CBlockIndex* pindexPrevWork = chainman.ActiveChain().Genesis();
150
+ while (pindex)
151
+ {
152
+ // Exponential moving average of recent proof-of-work block spacing
153
+ if (pindex->IsProofOfWork())
154
+ {
155
+ int64_t nActualSpacingWork = pindex->GetBlockTime() - pindexPrevWork->GetBlockTime();
156
+ nTargetSpacingWork = ((nInterval - 1) * nTargetSpacingWork + nActualSpacingWork + nActualSpacingWork) / (nInterval + 1);
157
+ nTargetSpacingWork = std::max(nTargetSpacingWork, nTargetSpacingWorkMin);
158
+ pindexPrevWork = pindex;
159
+ }
160
+ pindex = chainman.ActiveChain().Next(pindex);
161
+ }
162
+ double dNetworkGhps = GetDifficulty(pindex, chainman.ActiveChain().Tip()) * 4.294967296 / nTargetSpacingWork;
163
+ return dNetworkGhps;
164
+ },
165
+ };
166
+ }
167
+
119
168
  static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t& max_tries, unsigned int& extra_nonce, uint256& block_hash)
120
169
  {
121
170
  block_hash.SetNull();
@@ -147,7 +196,7 @@ static bool GenerateBlock(ChainstateManager& chainman, CBlock& block, uint64_t&
147
196
  return true;
148
197
  }
149
198
 
150
- static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& mempool, const CScript& coinbase_script, int nGenerate, uint64_t nMaxTries)
199
+ static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& mempool, const CScript& coinbase_script, int nGenerate, uint64_t nMaxTries, NodeContext* m_node)
151
200
  {
152
201
  int nHeightEnd = 0;
153
202
  int nHeight = 0;
@@ -161,7 +210,7 @@ static UniValue generateBlocks(ChainstateManager& chainman, const CTxMemPool& me
161
210
  UniValue blockHashes(UniValue::VARR);
162
211
  while (nHeight < nHeightEnd && !ShutdownRequested())
163
212
  {
164
- std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(chainman.ActiveChainstate(), mempool, Params()).CreateNewBlock(coinbase_script));
213
+ std::unique_ptr<CBlockTemplate> pblocktemplate(BlockAssembler(chainman.ActiveChainstate(), mempool, Params()).CreateNewBlock(coinbase_script,nullptr,nullptr,m_node));
165
214
  if (!pblocktemplate.get())
166
215
  throw JSONRPCError(RPC_INTERNAL_ERROR, "Couldn't create new block");
167
216
  CBlock *pblock = &pblocktemplate->block;
@@ -246,9 +295,9 @@ static RPCHelpMan generatetodescriptor()
246
295
  const CTxMemPool& mempool = EnsureMemPool(node);
247
296
  ChainstateManager& chainman = EnsureChainman(node);
248
297
 
249
- return generateBlocks(chainman, mempool, coinbase_script, num_blocks, max_tries);
298
+ return generateBlocks(chainman, mempool, coinbase_script, num_blocks, max_tries, &node);
250
299
  },
251
- };
300
+ };
252
301
  }
253
302
 
254
303
  static RPCHelpMan generate()
@@ -264,7 +313,7 @@ static RPCHelpMan generatetoaddress()
264
313
  "Mine to a specified address and return the block hashes.",
265
314
  {
266
315
  {"nblocks", RPCArg::Type::NUM, RPCArg::Optional::NO, "How many blocks are generated."},
267
- {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The address to send the newly generated bitcoin to."},
316
+ {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The address to send the newly generated peercoin to."},
268
317
  {"maxtries", RPCArg::Type::NUM, RPCArg::Default{DEFAULT_MAX_TRIES}, "How many iterations to try."},
269
318
  },
270
319
  RPCResult{
@@ -275,14 +324,13 @@ static RPCHelpMan generatetoaddress()
275
324
  RPCExamples{
276
325
  "\nGenerate 11 blocks to myaddress\n"
277
326
  + HelpExampleCli("generatetoaddress", "11 \"myaddress\"")
278
- + "If you are using the " PACKAGE_NAME " wallet, you can get a new address to send the newly generated bitcoin to with:\n"
327
+ + "If you are using the " PACKAGE_NAME " wallet, you can get a new address to send the newly generated peercoin to with:\n"
279
328
  + HelpExampleCli("getnewaddress", "")
280
329
  },
281
330
  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
282
331
  {
283
332
  const int num_blocks{request.params[0].get_int()};
284
333
  const uint64_t max_tries{request.params[2].isNull() ? DEFAULT_MAX_TRIES : request.params[2].get_int()};
285
-
286
334
  CTxDestination destination = DecodeDestination(request.params[1].get_str());
287
335
  if (!IsValidDestination(destination)) {
288
336
  throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Error: Invalid address");
@@ -294,7 +342,7 @@ static RPCHelpMan generatetoaddress()
294
342
 
295
343
  CScript coinbase_script = GetScriptForDestination(destination);
296
344
 
297
- return generateBlocks(chainman, mempool, coinbase_script, num_blocks, max_tries);
345
+ return generateBlocks(chainman, mempool, coinbase_script, num_blocks, max_tries, &node);
298
346
  },
299
347
  };
300
348
  }
@@ -443,8 +491,9 @@ static RPCHelpMan getmininginfo()
443
491
  obj.pushKV("blocks", active_chain.Height());
444
492
  if (BlockAssembler::m_last_block_weight) obj.pushKV("currentblockweight", *BlockAssembler::m_last_block_weight);
445
493
  if (BlockAssembler::m_last_block_num_txs) obj.pushKV("currentblocktx", *BlockAssembler::m_last_block_num_txs);
446
- obj.pushKV("difficulty", (double)GetDifficulty(active_chain.Tip()));
494
+ obj.pushKV("difficulty", (double)GetDifficulty(active_chain.Tip(), active_chain.Tip()));
447
495
  obj.pushKV("networkhashps", getnetworkhashps().HandleRequest(request));
496
+ obj.pushKV("networkghps", getnetworkghps().HandleRequest(request));
448
497
  obj.pushKV("pooledtx", (uint64_t)mempool.size());
449
498
  obj.pushKV("chain", Params().NetworkIDString());
450
499
  obj.pushKV("warnings", GetWarnings(false).original);
@@ -454,43 +503,6 @@ static RPCHelpMan getmininginfo()
454
503
  }
455
504
 
456
505
 
457
- // NOTE: Unlike wallet RPC (which use BTC values), mining RPCs follow GBT (BIP 22) in using satoshi amounts
458
- static RPCHelpMan prioritisetransaction()
459
- {
460
- return RPCHelpMan{"prioritisetransaction",
461
- "Accepts the transaction into mined blocks at a higher (or lower) priority\n",
462
- {
463
- {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The transaction id."},
464
- {"dummy", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "API-Compatibility for previous API. Must be zero or null.\n"
465
- " DEPRECATED. For forward compatibility use named arguments and omit this parameter."},
466
- {"fee_delta", RPCArg::Type::NUM, RPCArg::Optional::NO, "The fee value (in satoshis) to add (or subtract, if negative).\n"
467
- " Note, that this value is not a fee rate. It is a value to modify absolute fee of the TX.\n"
468
- " The fee is not actually paid, only the algorithm for selecting transactions into a block\n"
469
- " considers the transaction as it would have paid a higher (or lower) fee."},
470
- },
471
- RPCResult{
472
- RPCResult::Type::BOOL, "", "Returns true"},
473
- RPCExamples{
474
- HelpExampleCli("prioritisetransaction", "\"txid\" 0.0 10000")
475
- + HelpExampleRpc("prioritisetransaction", "\"txid\", 0.0, 10000")
476
- },
477
- [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
478
- {
479
- LOCK(cs_main);
480
-
481
- uint256 hash(ParseHashV(request.params[0], "txid"));
482
- CAmount nAmount = request.params[2].get_int64();
483
-
484
- if (!(request.params[1].isNull() || request.params[1].get_real() == 0)) {
485
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Priority is no longer supported, dummy argument to prioritisetransaction must be 0.");
486
- }
487
-
488
- EnsureAnyMemPool(request.context).PrioritiseTransaction(hash, nAmount);
489
- return true;
490
- },
491
- };
492
- }
493
-
494
506
 
495
507
  // NOTE: Assumes a conclusive result; if result is inconclusive, it must be handled by caller
496
508
  static UniValue BIP22ValidationResult(const BlockValidationState& state)
@@ -511,15 +523,6 @@ static UniValue BIP22ValidationResult(const BlockValidationState& state)
511
523
  return "valid?";
512
524
  }
513
525
 
514
- static std::string gbt_vb_name(const Consensus::DeploymentPos pos) {
515
- const struct VBDeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
516
- std::string s = vbinfo.name;
517
- if (!vbinfo.gbt_force) {
518
- s.insert(s.begin(), '!');
519
- }
520
- return s;
521
- }
522
-
523
526
  static RPCHelpMan getblocktemplate()
524
527
  {
525
528
  return RPCHelpMan{"getblocktemplate",
@@ -772,7 +775,7 @@ static RPCHelpMan getblocktemplate()
772
775
 
773
776
  // Create new block
774
777
  CScript scriptDummy = CScript() << OP_TRUE;
775
- pblocktemplate = BlockAssembler(active_chainstate, mempool, Params()).CreateNewBlock(scriptDummy);
778
+ pblocktemplate = BlockAssembler(active_chainstate, mempool, Params()).CreateNewBlock(scriptDummy, nullptr, nullptr, &node);
776
779
  if (!pblocktemplate)
777
780
  throw JSONRPCError(RPC_OUT_OF_MEMORY, "Out of memory");
778
781
 
@@ -783,11 +786,11 @@ static RPCHelpMan getblocktemplate()
783
786
  CBlock* pblock = &pblocktemplate->block; // pointer for convenience
784
787
 
785
788
  // Update nTime
786
- UpdateTime(pblock, consensusParams, pindexPrev);
789
+ UpdateTime(pblock);
787
790
  pblock->nNonce = 0;
788
791
 
789
792
  // NOTE: If at some point we support pre-segwit miners post-segwit-activation, this needs to take segwit support into consideration
790
- const bool fPreSegWit = !DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT);
793
+ const bool fPreSegWit = !IsBTC16BIPsEnabled(active_chain.Tip()->nTime);
791
794
 
792
795
  UniValue aCaps(UniValue::VARR); aCaps.push_back("proposal");
793
796
 
@@ -850,57 +853,12 @@ static RPCHelpMan getblocktemplate()
850
853
  aRules.push_back("!signet");
851
854
  }
852
855
 
853
- UniValue vbavailable(UniValue::VOBJ);
854
- for (int j = 0; j < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; ++j) {
855
- Consensus::DeploymentPos pos = Consensus::DeploymentPos(j);
856
- ThresholdState state = g_versionbitscache.State(pindexPrev, consensusParams, pos);
857
- switch (state) {
858
- case ThresholdState::DEFINED:
859
- case ThresholdState::FAILED:
860
- // Not exposed to GBT at all
861
- break;
862
- case ThresholdState::LOCKED_IN:
863
- // Ensure bit is set in block version
864
- pblock->nVersion |= g_versionbitscache.Mask(consensusParams, pos);
865
- [[fallthrough]];
866
- case ThresholdState::STARTED:
867
- {
868
- const struct VBDeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
869
- vbavailable.pushKV(gbt_vb_name(pos), consensusParams.vDeployments[pos].bit);
870
- if (setClientRules.find(vbinfo.name) == setClientRules.end()) {
871
- if (!vbinfo.gbt_force) {
872
- // If the client doesn't support this, don't indicate it in the [default] version
873
- pblock->nVersion &= ~g_versionbitscache.Mask(consensusParams, pos);
874
- }
875
- }
876
- break;
877
- }
878
- case ThresholdState::ACTIVE:
879
- {
880
- // Add to rules only
881
- const struct VBDeploymentInfo& vbinfo = VersionBitsDeploymentInfo[pos];
882
- aRules.push_back(gbt_vb_name(pos));
883
- if (setClientRules.find(vbinfo.name) == setClientRules.end()) {
884
- // Not supported by the client; make sure it's safe to proceed
885
- if (!vbinfo.gbt_force) {
886
- // If we do anything other than throw an exception here, be sure version/force isn't sent to old clients
887
- throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("Support for '%s' rule requires explicit client support", vbinfo.name));
888
- }
889
- }
890
- break;
891
- }
892
- }
893
- }
894
856
  result.pushKV("version", pblock->nVersion);
895
857
  result.pushKV("rules", aRules);
896
- result.pushKV("vbavailable", vbavailable);
897
- result.pushKV("vbrequired", int(0));
898
858
 
899
859
  if (nMaxVersionPreVB >= 2) {
900
- // If VB is supported by the client, nMaxVersionPreVB is -1, so we won't get here
901
860
  // Because BIP 34 changed how the generation transaction is serialized, we can only use version/force back to v2 blocks
902
861
  // This is safe to do [otherwise-]unconditionally only because we are throwing an exception above if a non-force deployment gets activated
903
- // Note that this can probably also be removed entirely after the first BIP9 non-force deployment (ie, probably segwit) gets activated
904
862
  aMutable.push_back("version/force");
905
863
  }
906
864
 
@@ -1006,6 +964,13 @@ static RPCHelpMan submitblock()
1006
964
  }
1007
965
  }
1008
966
 
967
+ // peercoin: check block before attempting to sign it
968
+ BlockValidationState state;
969
+ if (!CheckBlock(block, state, Params().GetConsensus(), true, true, false)) {
970
+ LogPrintf("SubmitBlock: %s\n", state.ToString());
971
+ throw JSONRPCError(-100, "Block failed CheckBlock() function.");
972
+ }
973
+
1009
974
  {
1010
975
  LOCK(cs_main);
1011
976
  const CBlockIndex* pindex = chainman.m_blockman.LookupBlockIndex(block.hashPrevBlock);
@@ -1059,7 +1024,8 @@ static RPCHelpMan submitheader()
1059
1024
  }
1060
1025
 
1061
1026
  BlockValidationState state;
1062
- chainman.ProcessNewBlockHeaders({h}, state, Params());
1027
+ int tmpTemp;
1028
+ chainman.ProcessNewBlockHeaders(tmpTemp, chainman.ActiveChain().Tip()->GetBlockHash(), {h}, state, Params());
1063
1029
  if (state.IsValid()) return NullUniValue;
1064
1030
  if (state.IsError()) {
1065
1031
  throw JSONRPCError(RPC_VERIFY_ERROR, state.ToString());
@@ -1084,7 +1050,7 @@ static RPCHelpMan estimatesmartfee()
1084
1050
  " higher feerate and is more likely to be sufficient for the desired\n"
1085
1051
  " target, but is not as responsive to short term drops in the\n"
1086
1052
  " prevailing fee market. Must be one of (case insensitive):\n"
1087
- "\"" + FeeModes("\"\n\"") + "\""},
1053
+ "\""},
1088
1054
  },
1089
1055
  RPCResult{
1090
1056
  RPCResult::Type::OBJ, "", "",
@@ -1109,159 +1075,14 @@ static RPCHelpMan estimatesmartfee()
1109
1075
  RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VSTR});
1110
1076
  RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
1111
1077
 
1112
- CBlockPolicyEstimator& fee_estimator = EnsureAnyFeeEstimator(request.context);
1113
- const NodeContext& node = EnsureAnyNodeContext(request.context);
1114
- const CTxMemPool& mempool = EnsureMemPool(node);
1115
-
1116
- unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
1117
- unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);
1118
- bool conservative = true;
1119
- if (!request.params[1].isNull()) {
1120
- FeeEstimateMode fee_mode;
1121
- if (!FeeModeFromString(request.params[1].get_str(), fee_mode)) {
1122
- throw JSONRPCError(RPC_INVALID_PARAMETER, InvalidEstimateModeErrorMessage());
1123
- }
1124
- if (fee_mode == FeeEstimateMode::ECONOMICAL) conservative = false;
1125
- }
1126
-
1127
- UniValue result(UniValue::VOBJ);
1128
- UniValue errors(UniValue::VARR);
1129
- FeeCalculation feeCalc;
1130
- CFeeRate feeRate{fee_estimator.estimateSmartFee(conf_target, &feeCalc, conservative)};
1131
- if (feeRate != CFeeRate(0)) {
1132
- CFeeRate min_mempool_feerate{mempool.GetMinFee(gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000)};
1133
- CFeeRate min_relay_feerate{::minRelayTxFee};
1134
- feeRate = std::max({feeRate, min_mempool_feerate, min_relay_feerate});
1135
- result.pushKV("feerate", ValueFromAmount(feeRate.GetFeePerK()));
1136
- } else {
1137
- errors.push_back("Insufficient data or no feerate found");
1138
- result.pushKV("errors", errors);
1139
- }
1140
- result.pushKV("blocks", feeCalc.returnedTarget);
1141
- return result;
1142
- },
1143
- };
1144
- }
1145
-
1146
- static RPCHelpMan estimaterawfee()
1147
- {
1148
- return RPCHelpMan{"estimaterawfee",
1149
- "\nWARNING: This interface is unstable and may disappear or change!\n"
1150
- "\nWARNING: This is an advanced API call that is tightly coupled to the specific\n"
1151
- " implementation of fee estimation. The parameters it can be called with\n"
1152
- " and the results it returns will change if the internal implementation changes.\n"
1153
- "\nEstimates the approximate fee per kilobyte needed for a transaction to begin\n"
1154
- "confirmation within conf_target blocks if possible. Uses virtual transaction size as\n"
1155
- "defined in BIP 141 (witness data is discounted).\n",
1156
- {
1157
- {"conf_target", RPCArg::Type::NUM, RPCArg::Optional::NO, "Confirmation target in blocks (1 - 1008)"},
1158
- {"threshold", RPCArg::Type::NUM, RPCArg::Default{0.95}, "The proportion of transactions in a given feerate range that must have been\n"
1159
- " confirmed within conf_target in order to consider those feerates as high enough and proceed to check\n"
1160
- " lower buckets."},
1161
- },
1162
- RPCResult{
1163
- RPCResult::Type::OBJ, "", "Results are returned for any horizon which tracks blocks up to the confirmation target",
1164
- {
1165
- {RPCResult::Type::OBJ, "short", /*optional=*/true, "estimate for short time horizon",
1166
- {
1167
- {RPCResult::Type::NUM, "feerate", /*optional=*/true, "estimate fee rate in " + CURRENCY_UNIT + "/kvB"},
1168
- {RPCResult::Type::NUM, "decay", "exponential decay (per block) for historical moving average of confirmation data"},
1169
- {RPCResult::Type::NUM, "scale", "The resolution of confirmation targets at this time horizon"},
1170
- {RPCResult::Type::OBJ, "pass", /*optional=*/true, "information about the lowest range of feerates to succeed in meeting the threshold",
1171
- {
1172
- {RPCResult::Type::NUM, "startrange", "start of feerate range"},
1173
- {RPCResult::Type::NUM, "endrange", "end of feerate range"},
1174
- {RPCResult::Type::NUM, "withintarget", "number of txs over history horizon in the feerate range that were confirmed within target"},
1175
- {RPCResult::Type::NUM, "totalconfirmed", "number of txs over history horizon in the feerate range that were confirmed at any point"},
1176
- {RPCResult::Type::NUM, "inmempool", "current number of txs in mempool in the feerate range unconfirmed for at least target blocks"},
1177
- {RPCResult::Type::NUM, "leftmempool", "number of txs over history horizon in the feerate range that left mempool unconfirmed after target"},
1178
- }},
1179
- {RPCResult::Type::OBJ, "fail", /*optional=*/true, "information about the highest range of feerates to fail to meet the threshold",
1180
- {
1181
- {RPCResult::Type::ELISION, "", ""},
1182
- }},
1183
- {RPCResult::Type::ARR, "errors", /*optional=*/true, "Errors encountered during processing (if there are any)",
1184
- {
1185
- {RPCResult::Type::STR, "error", ""},
1186
- }},
1187
- }},
1188
- {RPCResult::Type::OBJ, "medium", /*optional=*/true, "estimate for medium time horizon",
1189
- {
1190
- {RPCResult::Type::ELISION, "", ""},
1191
- }},
1192
- {RPCResult::Type::OBJ, "long", /*optional=*/true, "estimate for long time horizon",
1193
- {
1194
- {RPCResult::Type::ELISION, "", ""},
1195
- }},
1196
- }},
1197
- RPCExamples{
1198
- HelpExampleCli("estimaterawfee", "6 0.9")
1199
- },
1200
- [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
1201
- {
1202
- RPCTypeCheck(request.params, {UniValue::VNUM, UniValue::VNUM}, true);
1203
- RPCTypeCheckArgument(request.params[0], UniValue::VNUM);
1204
-
1205
- CBlockPolicyEstimator& fee_estimator = EnsureAnyFeeEstimator(request.context);
1206
-
1207
- unsigned int max_target = fee_estimator.HighestTargetTracked(FeeEstimateHorizon::LONG_HALFLIFE);
1208
- unsigned int conf_target = ParseConfirmTarget(request.params[0], max_target);
1209
- double threshold = 0.95;
1210
- if (!request.params[1].isNull()) {
1211
- threshold = request.params[1].get_real();
1212
- }
1213
- if (threshold < 0 || threshold > 1) {
1214
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid threshold");
1215
- }
1078
+ ChainstateManager& chainman = EnsureAnyChainman(request.context);
1216
1079
 
1217
1080
  UniValue result(UniValue::VOBJ);
1218
-
1219
- for (const FeeEstimateHorizon horizon : ALL_FEE_ESTIMATE_HORIZONS) {
1220
- CFeeRate feeRate;
1221
- EstimationResult buckets;
1222
-
1223
- // Only output results for horizons which track the target
1224
- if (conf_target > fee_estimator.HighestTargetTracked(horizon)) continue;
1225
-
1226
- feeRate = fee_estimator.estimateRawFee(conf_target, threshold, horizon, &buckets);
1227
- UniValue horizon_result(UniValue::VOBJ);
1228
- UniValue errors(UniValue::VARR);
1229
- UniValue passbucket(UniValue::VOBJ);
1230
- passbucket.pushKV("startrange", round(buckets.pass.start));
1231
- passbucket.pushKV("endrange", round(buckets.pass.end));
1232
- passbucket.pushKV("withintarget", round(buckets.pass.withinTarget * 100.0) / 100.0);
1233
- passbucket.pushKV("totalconfirmed", round(buckets.pass.totalConfirmed * 100.0) / 100.0);
1234
- passbucket.pushKV("inmempool", round(buckets.pass.inMempool * 100.0) / 100.0);
1235
- passbucket.pushKV("leftmempool", round(buckets.pass.leftMempool * 100.0) / 100.0);
1236
- UniValue failbucket(UniValue::VOBJ);
1237
- failbucket.pushKV("startrange", round(buckets.fail.start));
1238
- failbucket.pushKV("endrange", round(buckets.fail.end));
1239
- failbucket.pushKV("withintarget", round(buckets.fail.withinTarget * 100.0) / 100.0);
1240
- failbucket.pushKV("totalconfirmed", round(buckets.fail.totalConfirmed * 100.0) / 100.0);
1241
- failbucket.pushKV("inmempool", round(buckets.fail.inMempool * 100.0) / 100.0);
1242
- failbucket.pushKV("leftmempool", round(buckets.fail.leftMempool * 100.0) / 100.0);
1243
-
1244
- // CFeeRate(0) is used to indicate error as a return value from estimateRawFee
1245
- if (feeRate != CFeeRate(0)) {
1246
- horizon_result.pushKV("feerate", ValueFromAmount(feeRate.GetFeePerK()));
1247
- horizon_result.pushKV("decay", buckets.decay);
1248
- horizon_result.pushKV("scale", (int)buckets.scale);
1249
- horizon_result.pushKV("pass", passbucket);
1250
- // buckets.fail.start == -1 indicates that all buckets passed, there is no fail bucket to output
1251
- if (buckets.fail.start != -1) horizon_result.pushKV("fail", failbucket);
1252
- } else {
1253
- // Output only information that is still meaningful in the event of error
1254
- horizon_result.pushKV("decay", buckets.decay);
1255
- horizon_result.pushKV("scale", (int)buckets.scale);
1256
- horizon_result.pushKV("fail", failbucket);
1257
- errors.push_back("Insufficient data or no feerate found which meets threshold");
1258
- horizon_result.pushKV("errors",errors);
1259
- }
1260
- result.pushKV(StringForFeeEstimateHorizon(horizon), horizon_result);
1261
- }
1081
+ result.pushKV("feerate", 0.01);
1082
+ result.pushKV("blocks", chainman.ActiveChain().Height());
1262
1083
  return result;
1263
1084
  },
1264
- };
1085
+ };
1265
1086
  }
1266
1087
 
1267
1088
  void RegisterMiningRPCCommands(CRPCTable &t)
@@ -1272,7 +1093,6 @@ static const CRPCCommand commands[] =
1272
1093
  // --------------------- -----------------------
1273
1094
  { "mining", &getnetworkhashps, },
1274
1095
  { "mining", &getmininginfo, },
1275
- { "mining", &prioritisetransaction, },
1276
1096
  { "mining", &getblocktemplate, },
1277
1097
  { "mining", &submitblock, },
1278
1098
  { "mining", &submitheader, },
@@ -1283,8 +1103,6 @@ static const CRPCCommand commands[] =
1283
1103
  { "hidden", &generateblock, },
1284
1104
 
1285
1105
  { "util", &estimatesmartfee, },
1286
-
1287
- { "hidden", &estimaterawfee, },
1288
1106
  { "hidden", &generate, },
1289
1107
  };
1290
1108
  // clang-format on
src/rpc/misc.cpp CHANGED
@@ -41,15 +41,15 @@ static RPCHelpMan validateaddress()
41
41
  {
42
42
  return RPCHelpMan{
43
43
  "validateaddress",
44
- "\nReturn information about the given bitcoin address.\n",
44
+ "\nReturn information about the given peercoin address.\n",
45
45
  {
46
- {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to validate"},
46
+ {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The peercoin address to validate"},
47
47
  },
48
48
  RPCResult{
49
49
  RPCResult::Type::OBJ, "", "",
50
50
  {
51
51
  {RPCResult::Type::BOOL, "isvalid", "If the address is valid or not"},
52
- {RPCResult::Type::STR, "address", /*optional=*/true, "The bitcoin address validated"},
52
+ {RPCResult::Type::STR, "address", /*optional=*/true, "The peercoin address validated"},
53
53
  {RPCResult::Type::STR_HEX, "scriptPubKey", /*optional=*/true, "The hex-encoded scriptPubKey generated by the address"},
54
54
  {RPCResult::Type::BOOL, "isscript", /*optional=*/true, "If the key is a script"},
55
55
  {RPCResult::Type::BOOL, "iswitness", /*optional=*/true, "If the address is a witness address"},
@@ -316,7 +316,7 @@ static RPCHelpMan verifymessage()
316
316
  return RPCHelpMan{"verifymessage",
317
317
  "Verify a signed message.",
318
318
  {
319
- {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to use for the signature."},
319
+ {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The peercoin address to use for the signature."},
320
320
  {"signature", RPCArg::Type::STR, RPCArg::Optional::NO, "The signature provided by the signer in base 64 encoding (see signmessage)."},
321
321
  {"message", RPCArg::Type::STR, RPCArg::Optional::NO, "The message that was signed."},
322
322
  },
@@ -327,11 +327,11 @@ static RPCHelpMan verifymessage()
327
327
  "\nUnlock the wallet for 30 seconds\n"
328
328
  + HelpExampleCli("walletpassphrase", "\"mypassphrase\" 30") +
329
329
  "\nCreate the signature\n"
330
- + HelpExampleCli("signmessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"my message\"") +
330
+ + HelpExampleCli("signmessage", "\"PKRWHSDPDZHFJ9Mrjy65fPN3wL8YWQrD8q\" \"my message\"") +
331
331
  "\nVerify the signature\n"
332
- + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
332
+ + HelpExampleCli("verifymessage", "\"PKRWHSDPDZHFJ9Mrjy65fPN3wL8YWQrD8q\" \"signature\" \"my message\"") +
333
333
  "\nAs a JSON-RPC call\n"
334
- + HelpExampleRpc("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\", \"signature\", \"my message\"")
334
+ + HelpExampleRpc("verifymessage", "\"PKRWHSDPDZHFJ9Mrjy65fPN3wL8YWQrD8q\", \"signature\", \"my message\"")
335
335
  },
336
336
  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
337
337
  {
@@ -375,7 +375,7 @@ static RPCHelpMan signmessagewithprivkey()
375
375
  "\nCreate the signature\n"
376
376
  + HelpExampleCli("signmessagewithprivkey", "\"privkey\" \"my message\"") +
377
377
  "\nVerify the signature\n"
378
- + HelpExampleCli("verifymessage", "\"1D1ZrZNe3JUo7ZycKEYQQiQAWd9y54F4XX\" \"signature\" \"my message\"") +
378
+ + HelpExampleCli("verifymessage", "\"PKRWHSDPDZHFJ9Mrjy65fPN3wL8YWQrD8q\" \"signature\" \"my message\"") +
379
379
  "\nAs a JSON-RPC call\n"
380
380
  + HelpExampleRpc("signmessagewithprivkey", "\"privkey\", \"my message\"")
381
381
  },
@@ -675,7 +675,7 @@ static RPCHelpMan echo(const std::string& name)
675
675
  "\nSimply echo back the input arguments. This command is for testing.\n"
676
676
  "\nIt will return an internal bug report when arg9='trigger_internal_bug' is passed.\n"
677
677
  "\nThe difference between echo and echojson is that echojson has argument conversion enabled in the client-side table in "
678
- "bitcoin-cli and the GUI. There is no server-side difference.",
678
+ "peercoin-cli and the GUI. There is no server-side difference.",
679
679
  {
680
680
  {"arg0", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
681
681
  {"arg1", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, ""},
src/rpc/net.cpp CHANGED
@@ -28,6 +28,7 @@
28
28
  #include <version.h>
29
29
  #include <warnings.h>
30
30
 
31
+ #include <key_io.h>
31
32
  #include <optional>
32
33
 
33
34
  #include <univalue.h>
@@ -624,7 +625,7 @@ static RPCHelpMan getnetworkinfo()
624
625
  {
625
626
  LOCK(cs_main);
626
627
  UniValue obj(UniValue::VOBJ);
627
- obj.pushKV("version", CLIENT_VERSION);
628
+ obj.pushKV("version", FormatFullVersion());
628
629
  obj.pushKV("subversion", strSubVersion);
629
630
  obj.pushKV("protocolversion",PROTOCOL_VERSION);
630
631
  NodeContext& node = EnsureAnyNodeContext(request.context);
@@ -644,8 +645,6 @@ static RPCHelpMan getnetworkinfo()
644
645
  obj.pushKV("connections_out", (int)node.connman->GetNodeCount(ConnectionDirection::Out));
645
646
  }
646
647
  obj.pushKV("networks", GetNetworksInfo());
647
- obj.pushKV("relayfee", ValueFromAmount(::minRelayTxFee.GetFeePerK()));
648
- obj.pushKV("incrementalfee", ValueFromAmount(::incrementalRelayFee.GetFeePerK()));
649
648
  UniValue localAddresses(UniValue::VARR);
650
649
  {
651
650
  LOCK(g_maplocalhost_mutex);
src/rpc/protocol.h CHANGED
@@ -82,6 +82,8 @@ enum RPCErrorCode
82
82
  RPC_WALLET_ALREADY_LOADED = -35, //!< This same wallet is already loaded
83
83
  RPC_WALLET_ALREADY_EXISTS = -36, //!< There is already a wallet with the same name
84
84
 
85
+ //! peercoin
86
+ RPC_INSUFFICIENT_SEND_AMOUNT = -101, //! Transaction output is below minimum
85
87
  //! Backwards compatible aliases
86
88
  RPC_WALLET_INVALID_ACCOUNT_NAME = RPC_WALLET_INVALID_LABEL_NAME,
87
89
 
src/rpc/rawtransaction.cpp CHANGED
@@ -19,7 +19,6 @@
19
19
  #include <node/transaction.h>
20
20
  #include <policy/packages.h>
21
21
  #include <policy/policy.h>
22
- #include <policy/rbf.h>
23
22
  #include <primitives/transaction.h>
24
23
  #include <psbt.h>
25
24
  #include <random.h>
@@ -47,7 +46,6 @@
47
46
 
48
47
  using node::AnalyzePSBT;
49
48
  using node::BroadcastTransaction;
50
- using node::DEFAULT_MAX_RAW_TX_FEE_RATE;
51
49
  using node::FindCoins;
52
50
  using node::GetTransaction;
53
51
  using node::NodeContext;
@@ -71,7 +69,6 @@ static void TxToJSON(const CTransaction& tx, const uint256 hashBlock, UniValue&
71
69
  if (pindex) {
72
70
  if (active_chainstate.m_chain.Contains(pindex)) {
73
71
  entry.pushKV("confirmations", 1 + active_chainstate.m_chain.Height() - pindex->nHeight);
74
- entry.pushKV("time", pindex->GetBlockTime());
75
72
  entry.pushKV("blocktime", pindex->GetBlockTime());
76
73
  }
77
74
  else
@@ -122,7 +119,6 @@ static RPCHelpMan getrawtransaction()
122
119
  return RPCHelpMan{
123
120
  "getrawtransaction",
124
121
  "\nReturn the raw transaction data.\n"
125
-
126
122
  "\nBy default, this call only returns a transaction if it is in the mempool. If -txindex is enabled\n"
127
123
  "and no blockhash argument is passed, it will return the transaction if it is in the mempool or any block.\n"
128
124
  "If a blockhash argument is passed, it will return the transaction if\n"
@@ -182,7 +178,7 @@ static RPCHelpMan getrawtransaction()
182
178
  {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
183
179
  {RPCResult::Type::STR, "hex", "the hex"},
184
180
  {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
185
- {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
181
+ {RPCResult::Type::STR, "address", /*optional=*/true, "The Peercoin address (only if a well-defined address exists)"},
186
182
  }},
187
183
  }},
188
184
  }},
@@ -441,15 +437,11 @@ static RPCHelpMan createrawtransaction()
441
437
  UniValue::VARR,
442
438
  UniValueType(), // ARR or OBJ, checked later
443
439
  UniValue::VNUM,
444
- UniValue::VBOOL
440
+ UniValue::VNUM
445
441
  }, true
446
442
  );
447
443
 
448
- bool rbf = false;
449
- if (!request.params[3].isNull()) {
450
- rbf = request.params[3].isTrue();
451
- }
452
- CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf);
444
+ CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], request.params[3]);
453
445
 
454
446
  return EncodeHexTx(CTransaction(rawTx));
455
447
  },
@@ -511,7 +503,7 @@ static RPCHelpMan decoderawtransaction()
511
503
  {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
512
504
  {RPCResult::Type::STR_HEX, "hex", "the hex"},
513
505
  {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
514
- {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
506
+ {RPCResult::Type::STR, "address", /*optional=*/true, "The Peercoin address (only if a well-defined address exists)"},
515
507
  }},
516
508
  }},
517
509
  }},
@@ -556,7 +548,7 @@ static RPCHelpMan decodescript()
556
548
  {RPCResult::Type::STR, "asm", "Script public key"},
557
549
  {RPCResult::Type::STR, "desc", "Inferred descriptor for the script"},
558
550
  {RPCResult::Type::STR, "type", "The output type (e.g. " + GetAllOutputTypes() + ")"},
559
- {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
551
+ {RPCResult::Type::STR, "address", /*optional=*/true, "The Peercoin address (only if a well-defined address exists)"},
560
552
  {RPCResult::Type::STR, "p2sh", /*optional=*/true,
561
553
  "address of P2SH script wrapping this redeem script (not returned for types that should not be wrapped)"},
562
554
  {RPCResult::Type::OBJ, "segwit", /*optional=*/true,
@@ -846,7 +838,6 @@ static RPCHelpMan signrawtransactionwithkey()
846
838
  keystore.AddKey(key);
847
839
  }
848
840
 
849
- // Fetch previous transactions (inputs):
850
841
  std::map<COutPoint, Coin> coins;
851
842
  for (const CTxIn& txin : mtx.vin) {
852
843
  coins[txin.prevout]; // Create empty map entry keyed by prevout.
@@ -875,9 +866,6 @@ static RPCHelpMan sendrawtransaction()
875
866
  "\nRelated RPCs: createrawtransaction, signrawtransactionwithkey\n",
876
867
  {
877
868
  {"hexstring", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex string of the raw transaction"},
878
- {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
879
- "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT +
880
- "/kvB.\nSet to 0 to accept any fee rate.\n"},
881
869
  },
882
870
  RPCResult{
883
871
  RPCResult::Type::STR_HEX, "", "The transaction hash in hex"
@@ -896,7 +884,6 @@ static RPCHelpMan sendrawtransaction()
896
884
  {
897
885
  RPCTypeCheck(request.params, {
898
886
  UniValue::VSTR,
899
- UniValueType(), // VNUM or VSTR, checked inside AmountFromValue()
900
887
  });
901
888
 
902
889
  CMutableTransaction mtx;
@@ -905,17 +892,10 @@ static RPCHelpMan sendrawtransaction()
905
892
  }
906
893
  CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
907
894
 
908
- const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ?
909
- DEFAULT_MAX_RAW_TX_FEE_RATE :
910
- CFeeRate(AmountFromValue(request.params[1]));
911
-
912
- int64_t virtual_size = GetVirtualTransactionSize(*tx);
913
- CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
914
-
915
895
  std::string err_string;
916
896
  AssertLockNotHeld(cs_main);
917
897
  NodeContext& node = EnsureAnyNodeContext(request.context);
918
- const TransactionError err = BroadcastTransaction(node, tx, err_string, max_raw_tx_fee, /*relay*/ true, /*wait_callback*/ true);
898
+ const TransactionError err = BroadcastTransaction(node, tx, err_string, /*relay*/ true, /*wait_callback*/ true);
919
899
  if (TransactionError::OK != err) {
920
900
  throw JSONRPCTransactionError(err, err_string);
921
901
  }
@@ -940,8 +920,6 @@ static RPCHelpMan testmempoolaccept()
940
920
  {"rawtx", RPCArg::Type::STR_HEX, RPCArg::Optional::OMITTED, ""},
941
921
  },
942
922
  },
943
- {"maxfeerate", RPCArg::Type::AMOUNT, RPCArg::Default{FormatMoney(DEFAULT_MAX_RAW_TX_FEE_RATE.GetFeePerK())},
944
- "Reject transactions whose fee rate is higher than the specified value, expressed in " + CURRENCY_UNIT + "/kvB\n"},
945
923
  },
946
924
  RPCResult{
947
925
  RPCResult::Type::ARR, "", "The result of the mempool acceptance test for each raw transaction in the input array.\n"
@@ -978,7 +956,6 @@ static RPCHelpMan testmempoolaccept()
978
956
  {
979
957
  RPCTypeCheck(request.params, {
980
958
  UniValue::VARR,
981
- UniValueType(), // VNUM or VSTR, checked inside AmountFromValue()
982
959
  });
983
960
  const UniValue raw_transactions = request.params[0].get_array();
984
961
  if (raw_transactions.size() < 1 || raw_transactions.size() > MAX_PACKAGE_COUNT) {
@@ -986,10 +963,6 @@ static RPCHelpMan testmempoolaccept()
986
963
  "Array must contain between 1 and " + ToString(MAX_PACKAGE_COUNT) + " transactions.");
987
964
  }
988
965
 
989
- const CFeeRate max_raw_tx_fee_rate = request.params[1].isNull() ?
990
- DEFAULT_MAX_RAW_TX_FEE_RATE :
991
- CFeeRate(AmountFromValue(request.params[1]));
992
-
993
966
  std::vector<CTransactionRef> txns;
994
967
  txns.reserve(raw_transactions.size());
995
968
  for (const auto& rawtx : raw_transactions.getValues()) {
@@ -1038,20 +1011,13 @@ static RPCHelpMan testmempoolaccept()
1038
1011
  const CAmount fee = tx_result.m_base_fees.value();
1039
1012
  // Check that fee does not exceed maximum fee
1040
1013
  const int64_t virtual_size = tx_result.m_vsize.value();
1041
- const CAmount max_raw_tx_fee = max_raw_tx_fee_rate.GetFee(virtual_size);
1042
- if (max_raw_tx_fee && fee > max_raw_tx_fee) {
1043
- result_inner.pushKV("allowed", false);
1044
- result_inner.pushKV("reject-reason", "max-fee-exceeded");
1045
- exit_early = true;
1046
- } else {
1047
- // Only return the fee and vsize if the transaction would pass ATMP.
1048
- // These can be used to calculate the feerate.
1049
- result_inner.pushKV("allowed", true);
1050
- result_inner.pushKV("vsize", virtual_size);
1051
- UniValue fees(UniValue::VOBJ);
1052
- fees.pushKV("base", ValueFromAmount(fee));
1053
- result_inner.pushKV("fees", fees);
1054
- }
1014
+ // Only return the fee and vsize if the transaction would pass ATMP.
1015
+ // These can be used to calculate the feerate.
1016
+ result_inner.pushKV("allowed", true);
1017
+ result_inner.pushKV("vsize", virtual_size);
1018
+ UniValue fees(UniValue::VOBJ);
1019
+ fees.pushKV("base", ValueFromAmount(fee));
1020
+ result_inner.pushKV("fees", fees);
1055
1021
  } else {
1056
1022
  result_inner.pushKV("allowed", false);
1057
1023
  const TxValidationState state = tx_result.m_state;
@@ -1072,7 +1038,7 @@ static RPCHelpMan decodepsbt()
1072
1038
  {
1073
1039
  return RPCHelpMan{
1074
1040
  "decodepsbt",
1075
- "Return a JSON object representing the serialized, base64-encoded partially signed Bitcoin transaction.",
1041
+ "Return a JSON object representing the serialized, base64-encoded partially signed Peercoin transaction.",
1076
1042
  {
1077
1043
  {"psbt", RPCArg::Type::STR, RPCArg::Optional::NO, "The PSBT base64 string"},
1078
1044
  },
@@ -1124,7 +1090,7 @@ static RPCHelpMan decodepsbt()
1124
1090
  {RPCResult::Type::STR, "desc", "Inferred descriptor for the output"},
1125
1091
  {RPCResult::Type::STR_HEX, "hex", "The hex"},
1126
1092
  {RPCResult::Type::STR, "type", "The type, eg 'pubkeyhash'"},
1127
- {RPCResult::Type::STR, "address", /*optional=*/true, "The Bitcoin address (only if a well-defined address exists)"},
1093
+ {RPCResult::Type::STR, "address", /*optional=*/true, "The Peercoin address (only if a well-defined address exists)"},
1128
1094
  }},
1129
1095
  }},
1130
1096
  {RPCResult::Type::OBJ_DYN, "partial_signatures", /*optional=*/true, "",
@@ -1537,7 +1503,7 @@ static RPCHelpMan decodepsbt()
1537
1503
  static RPCHelpMan combinepsbt()
1538
1504
  {
1539
1505
  return RPCHelpMan{"combinepsbt",
1540
- "\nCombine multiple partially signed Bitcoin transactions into one transaction.\n"
1506
+ "\nCombine multiple partially signed Peercoin transactions into one transaction.\n"
1541
1507
  "Implements the Combiner role.\n",
1542
1508
  {
1543
1509
  {"txs", RPCArg::Type::ARR, RPCArg::Optional::NO, "The base64 strings of partially signed transactions",
@@ -1662,15 +1628,11 @@ static RPCHelpMan createpsbt()
1662
1628
  UniValue::VARR,
1663
1629
  UniValueType(), // ARR or OBJ, checked later
1664
1630
  UniValue::VNUM,
1665
- UniValue::VBOOL,
1631
+ UniValue::VNUM,
1666
1632
  }, true
1667
1633
  );
1668
1634
 
1669
- bool rbf = false;
1670
- if (!request.params[3].isNull()) {
1671
- rbf = request.params[3].isTrue();
1672
- }
1673
- CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf);
1635
+ CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], request.params[3]);
1674
1636
 
1675
1637
  // Make a blank psbt
1676
1638
  PartiallySignedTransaction psbtx;
@@ -2052,9 +2014,6 @@ static RPCHelpMan analyzepsbt()
2052
2014
  if (psbta.estimated_vsize != std::nullopt) {
2053
2015
  result.pushKV("estimated_vsize", (int)*psbta.estimated_vsize);
2054
2016
  }
2055
- if (psbta.estimated_feerate != std::nullopt) {
2056
- result.pushKV("estimated_feerate", ValueFromAmount(psbta.estimated_feerate->GetFeePerK()));
2057
- }
2058
2017
  if (psbta.fee != std::nullopt) {
2059
2018
  result.pushKV("fee", ValueFromAmount(*psbta.fee));
2060
2019
  }
src/rpc/rawtransaction_util.cpp CHANGED
@@ -17,11 +17,11 @@
17
17
  #include <script/signingprovider.h>
18
18
  #include <tinyformat.h>
19
19
  #include <univalue.h>
20
- #include <util/rbf.h>
21
20
  #include <util/strencodings.h>
21
+ #include <util/system.h>
22
22
  #include <util/translation.h>
23
23
 
24
- CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, bool rbf)
24
+ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& timestamp)
25
25
  {
26
26
  if (outputs_in.isNull()) {
27
27
  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, output argument must be non-null");
@@ -38,6 +38,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
38
38
  UniValue outputs = outputs_is_obj ? outputs_in.get_obj() : outputs_in.get_array();
39
39
 
40
40
  CMutableTransaction rawTx;
41
+ rawTx.nVersion = std::stoi(gArgs.GetArg("-txversion", std::to_string(CTransaction::CURRENT_VERSION)));
41
42
 
42
43
  if (!locktime.isNull()) {
43
44
  int64_t nLockTime = locktime.get_int64();
@@ -46,9 +47,17 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
46
47
  rawTx.nLockTime = nLockTime;
47
48
  }
48
49
 
50
+ if (!timestamp.isNull()) {
51
+ int64_t nTime = timestamp.get_int64();
52
+ if (nTime < 0 || nTime > LOCKTIME_MAX)
53
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, timestamp out of range");
54
+ rawTx.nTime = nTime;
55
+ }
56
+
49
57
  for (unsigned int idx = 0; idx < inputs.size(); idx++) {
50
58
  const UniValue& input = inputs[idx];
51
59
  const UniValue& o = input.get_obj();
60
+ CScript scriptSig;
52
61
 
53
62
  uint256 txid = ParseHashO(o, "txid");
54
63
 
@@ -60,9 +69,7 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
60
69
  throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter, vout cannot be negative");
61
70
 
62
71
  uint32_t nSequence;
63
- if (rbf) {
64
- nSequence = MAX_BIP125_RBF_SEQUENCE; /* CTxIn::SEQUENCE_FINAL - 2 */
65
- } else if (rawTx.nLockTime) {
72
+ if (rawTx.nLockTime) {
66
73
  nSequence = CTxIn::MAX_SEQUENCE_NONFINAL; /* CTxIn::SEQUENCE_FINAL - 1 */
67
74
  } else {
68
75
  nSequence = CTxIn::SEQUENCE_FINAL;
@@ -79,7 +86,15 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
79
86
  }
80
87
  }
81
88
 
82
- CTxIn in(COutPoint(txid, nOutput), CScript(), nSequence);
89
+ // set redeem script
90
+ const UniValue& rs = find_value(o, "redeemScript");
91
+ if (!rs.isNull()) {
92
+ std::vector<unsigned char> redeemScriptData(ParseHex(rs.getValStr()));
93
+ CScript redeemScript(redeemScriptData.begin(), redeemScriptData.end());
94
+ scriptSig = redeemScript;
95
+ }
96
+
97
+ CTxIn in(COutPoint(txid, nOutput), scriptSig, nSequence);
83
98
 
84
99
  rawTx.vin.push_back(in);
85
100
  }
@@ -114,10 +129,19 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
114
129
 
115
130
  CTxOut out(0, CScript() << OP_RETURN << data);
116
131
  rawTx.vout.push_back(out);
132
+ } else if (name_ == "coinstake") {
133
+ rawTx.nVersion = 1;
134
+ rawTx.vout.push_back(CTxOut(0, CScript()));
117
135
  } else {
118
136
  CTxDestination destination = DecodeDestination(name_);
119
137
  if (!IsValidDestination(destination)) {
120
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + name_);
138
+ if(name_.rfind("pubkey:",0) == 0) {
139
+ CScript scriptPubKey = CScript() << ToByteVector(ParseHex(name_.substr(7))) << OP_CHECKSIG;
140
+ CTxOut out(AmountFromValue(outputs[name_]), scriptPubKey);
141
+ rawTx.vout.push_back(out);
142
+ continue;
143
+ }
144
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Peercoin address: ") + name_);
121
145
  }
122
146
 
123
147
  if (!destinations.insert(destination).second) {
@@ -132,10 +156,6 @@ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniVal
132
156
  }
133
157
  }
134
158
 
135
- if (rbf && rawTx.vin.size() > 0 && !SignalsOptInRBF(CTransaction(rawTx))) {
136
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Invalid parameter combination: Sequence number(s) contradict replaceable option");
137
- }
138
-
139
159
  return rawTx;
140
160
  }
141
161
 
src/rpc/rawtransaction_util.h CHANGED
@@ -38,6 +38,6 @@ void SignTransactionResultToJSON(CMutableTransaction& mtx, bool complete, const
38
38
  void ParsePrevouts(const UniValue& prevTxsUnival, FillableSigningProvider* keystore, std::map<COutPoint, Coin>& coins);
39
39
 
40
40
  /** Create a transaction from univalue parameters */
41
- CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, bool rbf);
41
+ CMutableTransaction ConstructTransaction(const UniValue& inputs_in, const UniValue& outputs_in, const UniValue& locktime, const UniValue& timestamp);
42
42
 
43
43
  #endif // BITCOIN_RPC_RAWTRANSACTION_UTIL_H
src/rpc/server_util.cpp CHANGED
@@ -6,7 +6,6 @@
6
6
 
7
7
  #include <net_processing.h>
8
8
  #include <node/context.h>
9
- #include <policy/fees.h>
10
9
  #include <rpc/protocol.h>
11
10
  #include <rpc/request.h>
12
11
  #include <txmempool.h>
@@ -65,19 +64,6 @@ ChainstateManager& EnsureAnyChainman(const std::any& context)
65
64
  return EnsureChainman(EnsureAnyNodeContext(context));
66
65
  }
67
66
 
68
- CBlockPolicyEstimator& EnsureFeeEstimator(const NodeContext& node)
69
- {
70
- if (!node.fee_estimator) {
71
- throw JSONRPCError(RPC_INTERNAL_ERROR, "Fee estimation disabled");
72
- }
73
- return *node.fee_estimator;
74
- }
75
-
76
- CBlockPolicyEstimator& EnsureAnyFeeEstimator(const std::any& context)
77
- {
78
- return EnsureFeeEstimator(EnsureAnyNodeContext(context));
79
- }
80
-
81
67
  CConnman& EnsureConnman(const NodeContext& node)
82
68
  {
83
69
  if (!node.connman) {
src/rpc/util.cpp CHANGED
@@ -19,7 +19,7 @@
19
19
  #include <boost/algorithm/string/split.hpp>
20
20
 
21
21
  const std::string UNIX_EPOCH_TIME = "UNIX epoch time";
22
- const std::string EXAMPLE_ADDRESS[2] = {"bc1q09vm5lfy0j5reeulh4x5752q25uqqvz34hufdl", "bc1q02ad21edsxd23d32dfgqqsz4vv4nmtfzuklhy3"};
22
+ const std::string EXAMPLE_ADDRESS[2] = {"pc1q084czy2a0gnnahmn0s8xewhdzysqgxd5rm35uc", "pc1q8hjye3kge69kdqj0ev63myg9d9jnnpsj9tejq2"};
23
23
 
24
24
  std::string GetAllOutputTypes()
25
25
  {
@@ -165,7 +165,7 @@ std::string ShellQuoteIfNeeded(const std::string& s)
165
165
 
166
166
  std::string HelpExampleCli(const std::string& methodname, const std::string& args)
167
167
  {
168
- return "> bitcoin-cli " + methodname + " " + args + "\n";
168
+ return "> peercoin-cli " + methodname + " " + args + "\n";
169
169
  }
170
170
 
171
171
  std::string HelpExampleCliNamed(const std::string& methodname, const RPCArgList& args)
src/rpc/util.h CHANGED
@@ -91,7 +91,7 @@ std::vector<unsigned char> ParseHexO(const UniValue& o, std::string strKey);
91
91
  * @param[in] decimals Number of significant digits (default: 8).
92
92
  * @returns a CAmount if the various checks pass.
93
93
  */
94
- CAmount AmountFromValue(const UniValue& value, int decimals = 8);
94
+ CAmount AmountFromValue(const UniValue& value, int decimals = 6);
95
95
 
96
96
  using RPCArgList = std::vector<std::pair<std::string, UniValue>>;
97
97
  std::string HelpExampleCli(const std::string& methodname, const std::string& args);
src/script/interpreter.cpp CHANGED
@@ -1348,6 +1348,10 @@ public:
1348
1348
  void Serialize(S &s) const {
1349
1349
  // Serialize nVersion
1350
1350
  ::Serialize(s, txTo.nVersion);
1351
+ if (txTo.nVersion < 3) {
1352
+ // Serialize nTime
1353
+ ::Serialize(s, txTo.nTime);
1354
+ }
1351
1355
  // Serialize vin
1352
1356
  unsigned int nInputs = fAnyoneCanPay ? 1 : txTo.vin.size();
1353
1357
  ::WriteCompactSize(s, nInputs);
@@ -1620,6 +1624,10 @@ uint256 SignatureHash(const CScript& scriptCode, const T& txTo, unsigned int nIn
1620
1624
  CHashWriter ss(SER_GETHASH, 0);
1621
1625
  // Version
1622
1626
  ss << txTo.nVersion;
1627
+ if (txTo.nVersion < 3) {
1628
+ // nTime
1629
+ ss << txTo.nTime;
1630
+ }
1623
1631
  // Input prevouts/nSequence (none/all, depending on flags)
1624
1632
  ss << hashPrevouts;
1625
1633
  ss << hashSequence;
src/script/script.cpp CHANGED
@@ -7,6 +7,7 @@
7
7
 
8
8
  #include <util/strencodings.h>
9
9
 
10
+ #include <key.h>
10
11
  #include <string>
11
12
 
12
13
  std::string GetOpName(opcodetype opcode)
@@ -280,6 +281,19 @@ bool CScript::HasValidOps() const
280
281
  return true;
281
282
  }
282
283
 
284
+ void CScript::SetMultisig(int nRequired, const std::vector<CPubKey>& keys)
285
+ {
286
+ this->clear();
287
+
288
+ *this << EncodeOP_N(nRequired);
289
+ for (const auto& pubkey : keys)
290
+ {
291
+ std::vector<unsigned char> vchPubKey(pubkey.begin(), pubkey.end());
292
+ *this << vchPubKey;
293
+ }
294
+ *this << EncodeOP_N(keys.size()) << OP_CHECKMULTISIG;
295
+ }
296
+
283
297
  bool GetScriptOp(CScriptBase::const_iterator& pc, CScriptBase::const_iterator end, opcodetype& opcodeRet, std::vector<unsigned char>* pvchRet)
284
298
  {
285
299
  opcodeRet = OP_INVALIDOPCODE;
src/script/script.h CHANGED
@@ -20,6 +20,8 @@
20
20
  #include <string>
21
21
  #include <vector>
22
22
 
23
+ class CPubKey;
24
+
23
25
  // Maximum number of bytes pushable to the stack
24
26
  static const unsigned int MAX_SCRIPT_ELEMENT_SIZE = 520;
25
27
 
@@ -223,7 +225,7 @@ class CScriptNum
223
225
  * The semantics are subtle, though: operands must be in the range [-2^31 +1...2^31 -1],
224
226
  * but results may overflow (and are valid as long as they are not used in a subsequent
225
227
  * numeric operation). CScriptNum enforces those semantics by storing results as
226
- * an int64 and allowing out-of-range values to be returned as a vector of bytes but
228
+ * an int64_t and allowing out-of-range values to be returned as a vector of bytes but
227
229
  * throwing an exception if arithmetic is done or the result is interpreted as an integer.
228
230
  */
229
231
  public:
@@ -552,6 +554,8 @@ public:
552
554
  CScriptBase::clear();
553
555
  shrink_to_fit();
554
556
  }
557
+
558
+ void SetMultisig(int nRequired, const std::vector<CPubKey>& keys);
555
559
  };
556
560
 
557
561
  struct CScriptWitness
src/script/sign.cpp CHANGED
@@ -622,6 +622,10 @@ bool SignTransaction(CMutableTransaction& mtx, const SigningProvider* keystore,
622
622
  {
623
623
  bool fHashSingle = ((nHashType & ~SIGHASH_ANYONECANPAY) == SIGHASH_SINGLE);
624
624
 
625
+ // we don't need nTime anymore
626
+ if (mtx.nVersion >= 3)
627
+ mtx.nTime = 0;
628
+
625
629
  // Use CTransaction for the constant parts of the
626
630
  // transaction to avoid rehashing.
627
631
  const CTransaction txConst(mtx);
src/script/standard.h CHANGED
@@ -32,10 +32,10 @@ public:
32
32
  };
33
33
 
34
34
  /**
35
- * Default setting for nMaxDatacarrierBytes. 80 bytes of data, +1 for OP_RETURN,
35
+ * Default setting for nMaxDatacarrierBytes. 256 bytes of data, +1 for OP_RETURN,
36
36
  * +2 for the pushdata opcodes.
37
37
  */
38
- static const unsigned int MAX_OP_RETURN_RELAY = 83;
38
+ static const unsigned int MAX_OP_RETURN_RELAY = 259;
39
39
 
40
40
  /**
41
41
  * A data carrying output is an unspendable output containing data. The script
src/serialize.h CHANGED
@@ -131,6 +131,8 @@ enum
131
131
  SER_NETWORK = (1 << 0),
132
132
  SER_DISK = (1 << 1),
133
133
  SER_GETHASH = (1 << 2),
134
+
135
+ SER_POSMARKER = (1 << 18), // peercoin: for sending block headers with PoS marker, to allow headers-first syncronization
134
136
  };
135
137
 
136
138
  //! Convert the reference base type to X, without changing constness or reference type.
@@ -984,9 +986,10 @@ class CSizeComputer
984
986
  protected:
985
987
  size_t nSize;
986
988
 
989
+ const int nType;
987
990
  const int nVersion;
988
991
  public:
989
- explicit CSizeComputer(int nVersionIn) : nSize(0), nVersion(nVersionIn) {}
992
+ explicit CSizeComputer(int nTypeIn, int nVersionIn) : nSize(0), nType(nTypeIn), nVersion(nVersionIn) {}
990
993
 
991
994
  void write(Span<const std::byte> src)
992
995
  {
@@ -1010,6 +1013,7 @@ public:
1010
1013
  return nSize;
1011
1014
  }
1012
1015
 
1016
+ int GetType() const { return nType; }
1013
1017
  int GetVersion() const { return nVersion; }
1014
1018
  };
1015
1019
 
@@ -1083,15 +1087,15 @@ inline void WriteCompactSize(CSizeComputer &s, uint64_t nSize)
1083
1087
  }
1084
1088
 
1085
1089
  template <typename T>
1086
- size_t GetSerializeSize(const T& t, int nVersion = 0)
1090
+ size_t GetSerializeSize(const T& t, int nType, int nVersion = 0)
1087
1091
  {
1088
- return (CSizeComputer(nVersion) << t).size();
1092
+ return (CSizeComputer(nType, nVersion) << t).size();
1089
1093
  }
1090
1094
 
1091
1095
  template <typename... T>
1092
1096
  size_t GetSerializeSizeMany(int nVersion, const T&... t)
1093
1097
  {
1094
- CSizeComputer sc(nVersion);
1098
+ CSizeComputer sc(0, nVersion);
1095
1099
  SerializeMany(sc, t...);
1096
1100
  return sc.size();
1097
1101
  }
src/timedatadummy.cpp ADDED
@@ -0,0 +1,7 @@
1
+ #include <stdint.h>
2
+
3
+ // needed when linking transaction.cpp, since we are not going to pull real GetAdjustedTime from timedata.cpp
4
+ int64_t GetAdjustedTime()
5
+ {
6
+ return 0;
7
+ }
src/txdb.cpp CHANGED
@@ -322,7 +322,16 @@ bool CBlockTreeDB::LoadBlockIndexGuts(const Consensus::Params& consensusParams,
322
322
  pindexNew->nStatus = diskindex.nStatus;
323
323
  pindexNew->nTx = diskindex.nTx;
324
324
 
325
- if (!CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, consensusParams)) {
325
+ // peercoin related block index fields
326
+ pindexNew->nMint = diskindex.nMint;
327
+ pindexNew->nMoneySupply = diskindex.nMoneySupply;
328
+ pindexNew->nFlags = diskindex.nFlags;
329
+ pindexNew->nStakeModifier = diskindex.nStakeModifier;
330
+ pindexNew->prevoutStake = diskindex.prevoutStake;
331
+ pindexNew->nStakeTime = diskindex.nStakeTime;
332
+ pindexNew->hashProofOfStake = diskindex.hashProofOfStake;
333
+
334
+ if (pindexNew->IsProofOfWork() && !CheckProofOfWork(pindexNew->GetBlockHash(), pindexNew->nBits, consensusParams)) {
326
335
  return error("%s: CheckProofOfWork failed: %s", __func__, pindexNew->ToString());
327
336
  }
328
337
 
@@ -353,6 +362,12 @@ public:
353
362
  //! at which height this transaction was included in the active block chain
354
363
  int nHeight;
355
364
 
365
+ // peercoin: whether transaction is a coinstake
366
+ bool fCoinStake;
367
+
368
+ // peercoin: transaction timestamp
369
+ unsigned int nTime;
370
+
356
371
  //! empty constructor
357
372
  CCoins() : fCoinBase(false), vout(0), nHeight(0) { }
358
373
 
@@ -435,7 +450,7 @@ bool CCoinsViewDB::Upgrade() {
435
450
  COutPoint outpoint(key.second, 0);
436
451
  for (size_t i = 0; i < old_coins.vout.size(); ++i) {
437
452
  if (!old_coins.vout[i].IsNull() && !old_coins.vout[i].scriptPubKey.IsUnspendable()) {
438
- Coin newcoin(std::move(old_coins.vout[i]), old_coins.nHeight, old_coins.fCoinBase);
453
+ Coin newcoin(std::move(old_coins.vout[i]), old_coins.nHeight, old_coins.fCoinBase, old_coins.fCoinStake, old_coins.nTime);
439
454
  outpoint.n = i;
440
455
  CoinEntry entry(&outpoint);
441
456
  batch.Write(entry, newcoin);
src/txmempool.cpp CHANGED
@@ -10,15 +10,17 @@
10
10
  #include <consensus/consensus.h>
11
11
  #include <consensus/tx_verify.h>
12
12
  #include <consensus/validation.h>
13
- #include <policy/fees.h>
13
+ #include <kernel.h>
14
14
  #include <policy/policy.h>
15
15
  #include <policy/settings.h>
16
16
  #include <reverse_iterator.h>
17
+ #include <timedata.h>
17
18
  #include <util/moneystr.h>
18
19
  #include <util/system.h>
19
20
  #include <util/time.h>
20
21
  #include <validationinterface.h>
21
22
 
23
+ #include <chainparams.h>
22
24
  #include <cmath>
23
25
  #include <optional>
24
26
 
@@ -461,8 +463,8 @@ void CTxMemPoolEntry::UpdateAncestorState(int64_t modifySize, CAmount modifyFee,
461
463
  assert(int(nSigOpCostWithAncestors) >= 0);
462
464
  }
463
465
 
464
- CTxMemPool::CTxMemPool(CBlockPolicyEstimator* estimator, int check_ratio)
465
- : m_check_ratio(check_ratio), minerPolicyEstimator(estimator)
466
+ CTxMemPool::CTxMemPool(int check_ratio)
467
+ : m_check_ratio(check_ratio)
466
468
  {
467
469
  _clear(); //lock free clear
468
470
  }
@@ -483,7 +485,7 @@ void CTxMemPool::AddTransactionsUpdated(unsigned int n)
483
485
  nTransactionsUpdated += n;
484
486
  }
485
487
 
486
- void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAncestors, bool validFeeEstimate)
488
+ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAncestors)
487
489
  {
488
490
  // Add to memory pool without checking anything.
489
491
  // Used by AcceptToMemoryPool(), which DOES do
@@ -526,10 +528,6 @@ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, setEntries &setAnces
526
528
 
527
529
  nTransactionsUpdated++;
528
530
  totalTxSize += entry.GetTxSize();
529
- m_total_fee += entry.GetFee();
530
- if (minerPolicyEstimator) {
531
- minerPolicyEstimator->processTransaction(entry, validFeeEstimate);
532
- }
533
531
 
534
532
  vTxHashes.emplace_back(tx.GetWitnessHash(), newit);
535
533
  newit->vTxHashesIdx = vTxHashes.size() - 1;
@@ -549,12 +547,9 @@ void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)
549
547
  GetMainSignals().TransactionRemovedFromMempool(it->GetSharedTx(), reason, mempool_sequence);
550
548
  }
551
549
 
552
- const uint256 hash = it->GetTx().GetHash();
553
550
  for (const CTxIn& txin : it->GetTx().vin)
554
551
  mapNextTx.erase(txin.prevout);
555
552
 
556
- RemoveUnbroadcastTx(hash, true /* add logging because unchecked */ );
557
-
558
553
  if (vTxHashes.size() > 1) {
559
554
  vTxHashes[it->vTxHashesIdx] = std::move(vTxHashes.back());
560
555
  vTxHashes[it->vTxHashesIdx].second->vTxHashesIdx = it->vTxHashesIdx;
@@ -570,7 +565,6 @@ void CTxMemPool::removeUnchecked(txiter it, MemPoolRemovalReason reason)
570
565
  cachedInnerUsage -= memusage::DynamicUsage(it->GetMemPoolParentsConst()) + memusage::DynamicUsage(it->GetMemPoolChildrenConst());
571
566
  mapTx.erase(it);
572
567
  nTransactionsUpdated++;
573
- if (minerPolicyEstimator) {minerPolicyEstimator->removeTx(hash, false);}
574
568
  }
575
569
 
576
570
  // Calculates descendants of entry that are not already in setDescendants, and adds to
@@ -685,8 +679,6 @@ void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigne
685
679
  if (i != mapTx.end())
686
680
  entries.push_back(&*i);
687
681
  }
688
- // Before the txs in the new block have been removed from the mempool, update policy estimates
689
- if (minerPolicyEstimator) {minerPolicyEstimator->processBlock(nBlockHeight, entries);}
690
682
  for (const auto& tx : vtx)
691
683
  {
692
684
  txiter it = mapTx.find(tx->GetHash());
@@ -698,8 +690,6 @@ void CTxMemPool::removeForBlock(const std::vector<CTransactionRef>& vtx, unsigne
698
690
  removeConflicts(*tx);
699
691
  ClearPrioritisation(tx->GetHash());
700
692
  }
701
- lastRollingFeeUpdate = GetTime();
702
- blockSinceLastRollingFeeBump = true;
703
693
  }
704
694
 
705
695
  void CTxMemPool::_clear()
@@ -709,9 +699,6 @@ void CTxMemPool::_clear()
709
699
  totalTxSize = 0;
710
700
  m_total_fee = 0;
711
701
  cachedInnerUsage = 0;
712
- lastRollingFeeUpdate = GetTime();
713
- blockSinceLastRollingFeeBump = false;
714
- rollingMinimumFeeRate = 0;
715
702
  ++nTransactionsUpdated;
716
703
  }
717
704
 
@@ -812,9 +799,9 @@ void CTxMemPool::check(const CCoinsViewCache& active_coins_tip, int64_t spendhei
812
799
  TxValidationState dummy_state; // Not used. CheckTxInputs() should always pass
813
800
  CAmount txfee = 0;
814
801
  assert(!tx.IsCoinBase());
815
- assert(Consensus::CheckTxInputs(tx, dummy_state, mempoolDuplicate, spendheight, txfee));
802
+ assert(Consensus::CheckTxInputs(tx, dummy_state, mempoolDuplicate, spendheight, txfee, Params().GetConsensus(), tx.nTime ? tx.nTime : GetAdjustedTime()));
816
803
  for (const auto& input: tx.vin) mempoolDuplicate.SpendCoin(input.prevout);
817
- AddCoins(mempoolDuplicate, tx, std::numeric_limits<int>::max());
804
+ AddCoins(mempoolDuplicate, tx, std::numeric_limits<int>::max(), false, true);
818
805
  }
819
806
  for (auto it = mapNextTx.cbegin(); it != mapNextTx.cend(); it++) {
820
807
  uint256 hash = it->second->GetHash();
@@ -1016,7 +1003,7 @@ bool CCoinsViewMemPool::GetCoin(const COutPoint &outpoint, Coin &coin) const {
1016
1003
  CTransactionRef ptx = mempool.get(outpoint.hash);
1017
1004
  if (ptx) {
1018
1005
  if (outpoint.n < ptx->vout.size()) {
1019
- coin = Coin(ptx->vout[outpoint.n], MEMPOOL_HEIGHT, false);
1006
+ coin = Coin(ptx->vout[outpoint.n], MEMPOOL_HEIGHT, false, ptx->IsCoinStake(), ptx->nTime);
1020
1007
  return true;
1021
1008
  } else {
1022
1009
  return false;
@@ -1028,7 +1015,7 @@ bool CCoinsViewMemPool::GetCoin(const COutPoint &outpoint, Coin &coin) const {
1028
1015
  void CCoinsViewMemPool::PackageAddTransaction(const CTransactionRef& tx)
1029
1016
  {
1030
1017
  for (unsigned int n = 0; n < tx->vout.size(); ++n) {
1031
- m_temp_added.emplace(COutPoint(tx->GetHash(), n), Coin(tx->vout[n], MEMPOOL_HEIGHT, false));
1018
+ m_temp_added.emplace(COutPoint(tx->GetHash(), n), Coin(tx->vout[n], MEMPOOL_HEIGHT, false, tx->IsCoinStake(), tx->nTime));
1032
1019
  }
1033
1020
  }
1034
1021
 
@@ -1072,13 +1059,13 @@ int CTxMemPool::Expire(std::chrono::seconds time)
1072
1059
  return stage.size();
1073
1060
  }
1074
1061
 
1075
- void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry, bool validFeeEstimate)
1062
+ void CTxMemPool::addUnchecked(const CTxMemPoolEntry &entry)
1076
1063
  {
1077
1064
  setEntries setAncestors;
1078
1065
  uint64_t nNoLimit = std::numeric_limits<uint64_t>::max();
1079
1066
  std::string dummy;
1080
1067
  CalculateMemPoolAncestors(entry, setAncestors, nNoLimit, nNoLimit, nNoLimit, nNoLimit, dummy);
1081
- return addUnchecked(entry, setAncestors, validFeeEstimate);
1068
+ return addUnchecked(entry, setAncestors);
1082
1069
  }
1083
1070
 
1084
1071
  void CTxMemPool::UpdateChild(txiter entry, txiter child, bool add)
@@ -1103,55 +1090,13 @@ void CTxMemPool::UpdateParent(txiter entry, txiter parent, bool add)
1103
1090
  }
1104
1091
  }
1105
1092
 
1106
- CFeeRate CTxMemPool::GetMinFee(size_t sizelimit) const {
1107
- LOCK(cs);
1108
- if (!blockSinceLastRollingFeeBump || rollingMinimumFeeRate == 0)
1109
- return CFeeRate(llround(rollingMinimumFeeRate));
1110
-
1111
- int64_t time = GetTime();
1112
- if (time > lastRollingFeeUpdate + 10) {
1113
- double halflife = ROLLING_FEE_HALFLIFE;
1114
- if (DynamicMemoryUsage() < sizelimit / 4)
1115
- halflife /= 4;
1116
- else if (DynamicMemoryUsage() < sizelimit / 2)
1117
- halflife /= 2;
1118
-
1119
- rollingMinimumFeeRate = rollingMinimumFeeRate / pow(2.0, (time - lastRollingFeeUpdate) / halflife);
1120
- lastRollingFeeUpdate = time;
1121
-
1122
- if (rollingMinimumFeeRate < (double)incrementalRelayFee.GetFeePerK() / 2) {
1123
- rollingMinimumFeeRate = 0;
1124
- return CFeeRate(0);
1125
- }
1126
- }
1127
- return std::max(CFeeRate(llround(rollingMinimumFeeRate)), incrementalRelayFee);
1128
- }
1129
-
1130
- void CTxMemPool::trackPackageRemoved(const CFeeRate& rate) {
1131
- AssertLockHeld(cs);
1132
- if (rate.GetFeePerK() > rollingMinimumFeeRate) {
1133
- rollingMinimumFeeRate = rate.GetFeePerK();
1134
- blockSinceLastRollingFeeBump = false;
1135
- }
1136
- }
1137
-
1138
1093
  void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpendsRemaining) {
1139
1094
  AssertLockHeld(cs);
1140
1095
 
1141
1096
  unsigned nTxnRemoved = 0;
1142
- CFeeRate maxFeeRateRemoved(0);
1143
1097
  while (!mapTx.empty() && DynamicMemoryUsage() > sizelimit) {
1144
1098
  indexed_transaction_set::index<descendant_score>::type::iterator it = mapTx.get<descendant_score>().begin();
1145
1099
 
1146
- // We set the new mempool min fee to the feerate of the removed set, plus the
1147
- // "minimum reasonable fee rate" (ie some value under which we consider txn
1148
- // to have 0 fee). This way, we don't allow txn to enter mempool with feerate
1149
- // equal to txn which were removed with no block in between.
1150
- CFeeRate removed(it->GetModFeesWithDescendants(), it->GetSizeWithDescendants());
1151
- removed += incrementalRelayFee;
1152
- trackPackageRemoved(removed);
1153
- maxFeeRateRemoved = std::max(maxFeeRateRemoved, removed);
1154
-
1155
1100
  setEntries stage;
1156
1101
  CalculateDescendants(mapTx.project<0>(it), stage);
1157
1102
  nTxnRemoved += stage.size();
@@ -1172,10 +1117,6 @@ void CTxMemPool::TrimToSize(size_t sizelimit, std::vector<COutPoint>* pvNoSpends
1172
1117
  }
1173
1118
  }
1174
1119
  }
1175
-
1176
- if (maxFeeRateRemoved > CFeeRate(0)) {
1177
- LogPrint(BCLog::MEMPOOL, "Removed %u txn, rolling minimum fee bumped to %s\n", nTxnRemoved, maxFeeRateRemoved.ToString());
1178
- }
1179
1120
  }
1180
1121
 
1181
1122
  uint64_t CTxMemPool::CalculateDescendantMaximum(txiter entry) const {
src/txmempool.h CHANGED
@@ -17,7 +17,6 @@
17
17
  #include <coins.h>
18
18
  #include <consensus/amount.h>
19
19
  #include <indirectmap.h>
20
- #include <policy/feerate.h>
21
20
  #include <policy/packages.h>
22
21
  #include <primitives/transaction.h>
23
22
  #include <random.h>
@@ -318,8 +317,6 @@ struct entry_time {};
318
317
  struct ancestor_score {};
319
318
  struct index_by_wtxid {};
320
319
 
321
- class CBlockPolicyEstimator;
322
-
323
320
  /**
324
321
  * Information about a mempool transaction.
325
322
  */
@@ -361,9 +358,6 @@ enum class MemPoolRemovalReason {
361
358
  * local node), but not all transactions seen are added to the pool. For
362
359
  * example, the following new transactions will not be added to the mempool:
363
360
  * - a transaction which doesn't meet the minimum fee requirements.
364
- * - a new transaction that double-spends an input of a transaction already in
365
- * the pool where the new transaction does not meet the Replace-By-Fee
366
- * requirements as defined in BIP 125.
367
361
  * - a non-standard transaction.
368
362
  *
369
363
  * CTxMemPool::mapTx, and CTxMemPoolEntry bookkeeping:
@@ -431,24 +425,17 @@ class CTxMemPool
431
425
  protected:
432
426
  const int m_check_ratio; //!< Value n means that 1 times in n we check.
433
427
  std::atomic<unsigned int> nTransactionsUpdated{0}; //!< Used by getblocktemplate to trigger CreateNewBlock() invocation
434
- CBlockPolicyEstimator* const minerPolicyEstimator;
435
428
 
436
429
  uint64_t totalTxSize GUARDED_BY(cs); //!< sum of all mempool tx's virtual sizes. Differs from serialized tx size since witness data is discounted. Defined in BIP 141.
437
430
  CAmount m_total_fee GUARDED_BY(cs); //!< sum of all mempool tx's fees (NOT modified fee)
438
431
  uint64_t cachedInnerUsage GUARDED_BY(cs); //!< sum of dynamic memory usage of all the map elements (NOT the maps themselves)
439
432
 
440
- mutable int64_t lastRollingFeeUpdate GUARDED_BY(cs);
441
- mutable bool blockSinceLastRollingFeeBump GUARDED_BY(cs);
442
- mutable double rollingMinimumFeeRate GUARDED_BY(cs); //!< minimum fee to get into the pool, decreases exponentially
443
433
  mutable Epoch m_epoch GUARDED_BY(cs);
444
-
445
434
  // In-memory counter for external mempool tracking purposes.
446
435
  // This number is incremented once every time a transaction
447
436
  // is added or removed from the mempool for any reason.
448
437
  mutable uint64_t m_sequence_number GUARDED_BY(cs){1};
449
438
 
450
- void trackPackageRemoved(const CFeeRate& rate) EXCLUSIVE_LOCKS_REQUIRED(cs);
451
-
452
439
  bool m_is_loaded GUARDED_BY(cs){false};
453
440
 
454
441
  public:
@@ -568,7 +555,7 @@ public:
568
555
  * @param[in] estimator is used to estimate appropriate transaction fees.
569
556
  * @param[in] check_ratio is the ratio used to determine how often sanity checks will run.
570
557
  */
571
- explicit CTxMemPool(CBlockPolicyEstimator* estimator = nullptr, int check_ratio = 0);
558
+ explicit CTxMemPool(int check_ratio = 0);
572
559
 
573
560
  /**
574
561
  * If sanity-checking is turned on, check makes sure the pool is
@@ -585,8 +572,8 @@ public:
585
572
  // Note that addUnchecked is ONLY called from ATMP outside of tests
586
573
  // and any other callers may break wallet's in-mempool tracking (due to
587
574
  // lack of CValidationInterface::TransactionAddedToMempool callbacks).
588
- void addUnchecked(const CTxMemPoolEntry& entry, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
589
- void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors, bool validFeeEstimate = true) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
575
+ void addUnchecked(const CTxMemPoolEntry& entry) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
576
+ void addUnchecked(const CTxMemPoolEntry& entry, setEntries& setAncestors) EXCLUSIVE_LOCKS_REQUIRED(cs, cs_main);
590
577
 
591
578
  void removeRecursive(const CTransaction& tx, MemPoolRemovalReason reason) EXCLUSIVE_LOCKS_REQUIRED(cs);
592
579
  /** After reorg, filter the entries that would no longer be valid in the next block, and update
@@ -695,14 +682,6 @@ public:
695
682
  * already in it. */
696
683
  void CalculateDescendants(txiter it, setEntries& setDescendants) const EXCLUSIVE_LOCKS_REQUIRED(cs);
697
684
 
698
- /** The minimum fee to get into the mempool, which may itself not be enough
699
- * for larger-sized transactions.
700
- * The incrementalRelayFee policy variable is used to bound the time it
701
- * takes the fee rate to go back down all the way to 0. When the feerate
702
- * would otherwise be half of this, it is set to 0 instead.
703
- */
704
- CFeeRate GetMinFee(size_t sizelimit) const;
705
-
706
685
  /** Remove transactions from the mempool until its dynamic size is <= sizelimit.
707
686
  * pvNoSpendsRemaining, if set, will be populated with the list of outpoints
708
687
  * which are not in mempool which no longer have any spends in this mempool.
src/uint256.h CHANGED
@@ -22,6 +22,11 @@ protected:
22
22
  static constexpr int WIDTH = BITS / 8;
23
23
  uint8_t m_data[WIDTH];
24
24
  public:
25
+ const uint32_t *GetDataPtr() const
26
+ {
27
+ return (const uint32_t *)m_data;
28
+ }
29
+
25
30
  /* construct 0 value by default */
26
31
  constexpr base_blob() : m_data() {}
27
32
 
src/undo.h CHANGED
@@ -24,7 +24,8 @@ struct TxInUndoFormatter
24
24
  {
25
25
  template<typename Stream>
26
26
  void Ser(Stream &s, const Coin& txout) {
27
- ::Serialize(s, VARINT(txout.nHeight * uint32_t{2} + txout.fCoinBase ));
27
+ ::Serialize(s, VARINT(txout.nHeight * uint32_t{4} + txout.fCoinBase + (txout.fCoinStake ? 2u : 0u)));
28
+ ::Serialize(s, VARINT(txout.nTime));
28
29
  if (txout.nHeight > 0) {
29
30
  // Required to maintain compatibility with older undo format.
30
31
  ::Serialize(s, (unsigned char)0);
@@ -36,8 +37,10 @@ struct TxInUndoFormatter
36
37
  void Unser(Stream &s, Coin& txout) {
37
38
  uint32_t nCode = 0;
38
39
  ::Unserialize(s, VARINT(nCode));
39
- txout.nHeight = nCode >> 1;
40
+ txout.nHeight = nCode >> 2;
40
41
  txout.fCoinBase = nCode & 1;
42
+ txout.fCoinStake = nCode & 2;
43
+ ::Unserialize(s, VARINT(txout.nTime));
41
44
  if (txout.nHeight > 0) {
42
45
  // Old versions stored the version number for the last spend of
43
46
  // a transaction's outputs. Non-final spends were indicated with
src/util.h ADDED
@@ -0,0 +1,74 @@
1
+ /**********************************************************************
2
+ * Copyright (c) 2018 Pieter Wuille, Greg Maxwell, Gleb Naumenko *
3
+ * Distributed under the MIT software license, see the accompanying *
4
+ * file LICENSE or http://www.opensource.org/licenses/mit-license.php.*
5
+ **********************************************************************/
6
+
7
+ #ifndef _MINISKETCH_UTIL_H_
8
+ #define _MINISKETCH_UTIL_H_
9
+
10
+ #ifdef MINISKETCH_VERIFY
11
+ #include <stdio.h>
12
+ #endif
13
+
14
+ #if !defined(__GNUC_PREREQ)
15
+ # if defined(__GNUC__)&&defined(__GNUC_MINOR__)
16
+ # define __GNUC_PREREQ(_maj,_min) \
17
+ ((__GNUC__<<16)+__GNUC_MINOR__>=((_maj)<<16)+(_min))
18
+ # else
19
+ # define __GNUC_PREREQ(_maj,_min) 0
20
+ # endif
21
+ #endif
22
+
23
+ #if __GNUC_PREREQ(3, 0)
24
+ #define EXPECT(x,c) __builtin_expect((x),(c))
25
+ #else
26
+ #define EXPECT(x,c) (x)
27
+ #endif
28
+
29
+ /* Assertion macros */
30
+
31
+ /**
32
+ * Unconditional failure on condition failure.
33
+ * Primarily used in testing harnesses.
34
+ */
35
+ #define CHECK(cond) do { \
36
+ if (EXPECT(!(cond), 0)) { \
37
+ fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, "Check condition failed: " #cond); \
38
+ abort(); \
39
+ } \
40
+ } while(0)
41
+
42
+ /**
43
+ * Check macro that does nothing in normal non-verify builds but crashes in verify builds.
44
+ * This is used to test conditions at runtime that should always be true, but are either
45
+ * expensive to test or in locations where returning on failure would be messy.
46
+ */
47
+ #ifdef MINISKETCH_VERIFY
48
+ #define CHECK_SAFE(cond) CHECK(cond)
49
+ #else
50
+ #define CHECK_SAFE(cond)
51
+ #endif
52
+
53
+ /**
54
+ * Check a condition and return on failure in non-verify builds, crash in verify builds.
55
+ * Used for inexpensive conditions which believed to be always true in locations where
56
+ * a graceful exit is possible.
57
+ */
58
+ #ifdef MINISKETCH_VERIFY
59
+ #define CHECK_RETURN(cond, rvar) do { \
60
+ if (EXPECT(!(cond), 0)) { \
61
+ fprintf(stderr, "%s:%d: %s\n", __FILE__, __LINE__, "Check condition failed: " #cond); \
62
+ abort(); \
63
+ return rvar; /* Does nothing, but causes compile to warn on incorrect return types. */ \
64
+ } \
65
+ } while(0)
66
+ #else
67
+ #define CHECK_RETURN(cond, rvar) do { \
68
+ if (EXPECT(!(cond), 0)) { \
69
+ return rvar; \
70
+ } \
71
+ } while(0)
72
+ #endif
73
+
74
+ #endif
src/util/error.cpp CHANGED
@@ -29,8 +29,6 @@ bilingual_str TransactionErrorString(const TransactionError err)
29
29
  return Untranslated("PSBTs not compatible (different transactions)");
30
30
  case TransactionError::SIGHASH_MISMATCH:
31
31
  return Untranslated("Specified sighash value does not match value stored in PSBT");
32
- case TransactionError::MAX_FEE_EXCEEDED:
33
- return Untranslated("Fee exceeds maximum configured by user (e.g. -maxtxfee, maxfeerate)");
34
32
  case TransactionError::EXTERNAL_SIGNER_NOT_FOUND:
35
33
  return Untranslated("External signer not found");
36
34
  case TransactionError::EXTERNAL_SIGNER_FAILED:
src/util/error.h CHANGED
@@ -29,7 +29,6 @@ enum class TransactionError {
29
29
  INVALID_PSBT,
30
30
  PSBT_MISMATCH,
31
31
  SIGHASH_MISMATCH,
32
- MAX_FEE_EXCEEDED,
33
32
  EXTERNAL_SIGNER_NOT_FOUND,
34
33
  EXTERNAL_SIGNER_FAILED,
35
34
  };
src/util/message.cpp CHANGED
@@ -19,7 +19,7 @@
19
19
  * Text used to signify that a signed message follows and to prevent
20
20
  * inadvertently signing a transaction.
21
21
  */
22
- const std::string MESSAGE_MAGIC = "Bitcoin Signed Message:\n";
22
+ const std::string MESSAGE_MAGIC = "Peercoin Signed Message:\n";
23
23
 
24
24
  MessageVerificationResult MessageVerify(
25
25
  const std::string& address,
src/util/moneystr.cpp CHANGED
@@ -23,7 +23,7 @@ std::string FormatMoney(const CAmount n)
23
23
  quotient = -quotient;
24
24
  remainder = -remainder;
25
25
  }
26
- std::string str = strprintf("%d.%08d", quotient, remainder);
26
+ std::string str = strprintf("%d.%06d", quotient, remainder);
27
27
 
28
28
  // Right-trim excess zeros before the decimal point:
29
29
  int nTrim = 0;
src/util/strencodings.cpp CHANGED
@@ -426,13 +426,17 @@ bool ParseFixedPoint(const std::string &val, int decimals, int64_t *amount_out)
426
426
  if (ptr < end && val[ptr] == '.')
427
427
  {
428
428
  ++ptr;
429
+ int peercoin_digits = 6;
429
430
  if (ptr < end && IsDigit(val[ptr]))
430
431
  {
431
432
  while (ptr < end && IsDigit(val[ptr])) {
432
- if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
433
- return false; /* overflow */
433
+ if (peercoin_digits) {
434
+ if (!ProcessMantissaDigit(val[ptr], mantissa, mantissa_tzeros))
435
+ return false; /* overflow */
436
+ ++point_ofs;
437
+ --peercoin_digits;
438
+ }
434
439
  ++ptr;
435
- ++point_ofs;
436
440
  }
437
441
  } else return false; /* missing expected digit */
438
442
  }
src/util/system.cpp CHANGED
@@ -90,7 +90,7 @@
90
90
  // Application startup time (used for uptime calculation)
91
91
  const int64_t nStartupTime = GetTime();
92
92
 
93
- const char * const BITCOIN_CONF_FILENAME = "bitcoin.conf";
93
+ const char * const BITCOIN_CONF_FILENAME = "peercoin.conf";
94
94
  const char * const BITCOIN_SETTINGS_FILENAME = "settings.json";
95
95
 
96
96
  ArgsManager gArgs;
@@ -775,7 +775,7 @@ static std::string FormatException(const std::exception* pex, const char* pszThr
775
775
  char pszModule[MAX_PATH] = "";
776
776
  GetModuleFileNameA(nullptr, pszModule, sizeof(pszModule));
777
777
  #else
778
- const char* pszModule = "bitcoin";
778
+ const char* pszModule = "peercoin";
779
779
  #endif
780
780
  if (pex)
781
781
  return strprintf(
@@ -794,12 +794,13 @@ void PrintExceptionContinue(const std::exception* pex, const char* pszThread)
794
794
 
795
795
  fs::path GetDefaultDataDir()
796
796
  {
797
- // Windows: C:\Users\Username\AppData\Roaming\Bitcoin
798
- // macOS: ~/Library/Application Support/Bitcoin
799
- // Unix-like: ~/.bitcoin
797
+ // Windows < Vista: C:\Documents and Settings\Username\Application Data\Peercoin
798
+ // Windows >= Vista: C:\Users\Username\AppData\Roaming\Peercoin
799
+ // Mac: ~/Library/Application Support/Peercoin
800
+ // Unix: ~/.peercoin
800
801
  #ifdef WIN32
801
802
  // Windows
802
- return GetSpecialFolderPath(CSIDL_APPDATA) / "Bitcoin";
803
+ return GetSpecialFolderPath(CSIDL_APPDATA) / "Peercoin";
803
804
  #else
804
805
  fs::path pathRet;
805
806
  char* pszHome = getenv("HOME");
@@ -808,11 +809,11 @@ fs::path GetDefaultDataDir()
808
809
  else
809
810
  pathRet = fs::path(pszHome);
810
811
  #ifdef MAC_OSX
811
- // macOS
812
- return pathRet / "Library/Application Support/Bitcoin";
812
+ // Mac
813
+ return pathRet / "Library/Application Support/Peercoin";
813
814
  #else
814
- // Unix-like
815
- return pathRet / ".bitcoin";
815
+ // Unix
816
+ return pathRet / ".peercoin";
816
817
  #endif
817
818
  #endif
818
819
  }
src/validation.cpp CHANGED
@@ -16,18 +16,18 @@
16
16
  #include <consensus/tx_verify.h>
17
17
  #include <consensus/validation.h>
18
18
  #include <cuckoocache.h>
19
- #include <deploymentstatus.h>
20
19
  #include <flatfile.h>
21
20
  #include <hash.h>
22
21
  #include <index/blockfilterindex.h>
22
+ #include <index/txindex.h>
23
23
  #include <logging.h>
24
24
  #include <logging/timer.h>
25
+ #include <net.h>
25
26
  #include <node/blockstorage.h>
26
27
  #include <node/coinstats.h>
27
28
  #include <node/ui_interface.h>
28
29
  #include <node/utxo_snapshot.h>
29
30
  #include <policy/policy.h>
30
- #include <policy/rbf.h>
31
31
  #include <policy/settings.h>
32
32
  #include <pow.h>
33
33
  #include <primitives/block.h>
@@ -47,7 +47,6 @@
47
47
  #include <util/check.h> // For NDEBUG compile time check
48
48
  #include <util/hasher.h>
49
49
  #include <util/moneystr.h>
50
- #include <util/rbf.h>
51
50
  #include <util/strencodings.h>
52
51
  #include <util/system.h>
53
52
  #include <util/trace.h>
@@ -58,6 +57,10 @@
58
57
  #include <algorithm>
59
58
  #include <numeric>
60
59
  #include <optional>
60
+ #include <kernel.h>
61
+ #include <bignum.h>
62
+ #include <wallet/wallet.h>
63
+
61
64
  #include <string>
62
65
 
63
66
  #include <boost/algorithm/string/replace.hpp>
@@ -74,12 +77,8 @@ using node::ReadBlockFromDisk;
74
77
  using node::SnapshotMetadata;
75
78
  using node::UNDOFILE_CHUNK_SIZE;
76
79
  using node::UndoReadFromDisk;
77
- using node::UnlinkPrunedFiles;
78
- using node::fHavePruned;
79
80
  using node::fImporting;
80
- using node::fPruneMode;
81
81
  using node::fReindex;
82
- using node::nPruneTarget;
83
82
 
84
83
  #define MICRO 0.000001
85
84
  #define MILLI 0.001
@@ -109,8 +108,8 @@ const std::vector<std::string> CHECKLEVEL_DOC {
109
108
 
110
109
  bool CBlockIndexWorkComparator::operator()(const CBlockIndex *pa, const CBlockIndex *pb) const {
111
110
  // First sort by most total work, ...
112
- if (pa->nChainWork > pb->nChainWork) return false;
113
- if (pa->nChainWork < pb->nChainWork) return true;
111
+ if (pa->nChainTrust > pb->nChainTrust) return false;
112
+ if (pa->nChainTrust < pb->nChainTrust) return true;
114
113
 
115
114
  // ... then by earliest time received, ...
116
115
  if (pa->nSequenceId < pb->nSequenceId) return false;
@@ -125,6 +124,7 @@ bool CBlockIndexWorkComparator::operator()(const CBlockIndex *pa, const CBlockIn
125
124
  return false;
126
125
  }
127
126
 
127
+ uint256 vStakeSeen[1024];
128
128
  /**
129
129
  * Mutex to guard access to validation specific variables, such as reading
130
130
  * or changing the chainstate.
@@ -150,8 +150,7 @@ int64_t nMaxTipAge = DEFAULT_MAX_TIP_AGE;
150
150
  uint256 hashAssumeValid;
151
151
  arith_uint256 nMinimumChainWork;
152
152
 
153
- CFeeRate minRelayTxFee = CFeeRate(DEFAULT_MIN_RELAY_TX_FEE);
154
-
153
+ CTxMemPool mempool;
155
154
  CBlockIndex* CChainState::FindForkInGlobalIndex(const CBlockLocator& locator) const
156
155
  {
157
156
  AssertLockHeld(cs_main);
@@ -301,18 +300,6 @@ static void LimitMempoolSize(CTxMemPool& pool, CCoinsViewCache& coins_cache, siz
301
300
  coins_cache.Uncache(removed);
302
301
  }
303
302
 
304
- static bool IsCurrentForFeeEstimation(CChainState& active_chainstate) EXCLUSIVE_LOCKS_REQUIRED(cs_main)
305
- {
306
- AssertLockHeld(cs_main);
307
- if (active_chainstate.IsInitialBlockDownload())
308
- return false;
309
- if (active_chainstate.m_chain.Tip()->GetBlockTime() < count_seconds(GetTime<std::chrono::seconds>() - MAX_FEE_ESTIMATION_TIP_AGE))
310
- return false;
311
- if (active_chainstate.m_chain.Height() < pindexBestHeader->nHeight - 1)
312
- return false;
313
- return true;
314
- }
315
-
316
303
  void CChainState::MaybeUpdateMempoolForReorg(
317
304
  DisconnectedBlockTransactions& disconnectpool,
318
305
  bool fAddToMempool)
@@ -331,7 +318,7 @@ void CChainState::MaybeUpdateMempoolForReorg(
331
318
  auto it = disconnectpool.queuedTx.get<insertion_order>().rbegin();
332
319
  while (it != disconnectpool.queuedTx.get<insertion_order>().rend()) {
333
320
  // ignore validation errors in resurrected transactions
334
- if (!fAddToMempool || (*it)->IsCoinBase() ||
321
+ if (!fAddToMempool || (*it)->IsCoinBase() || (*it)->IsCoinStake() ||
335
322
  AcceptToMemoryPool(*this, *it, GetTime(),
336
323
  /*bypass_limits=*/true, /*test_accept=*/false).m_result_type !=
337
324
  MempoolAcceptResult::ResultType::VALID) {
@@ -423,7 +410,7 @@ static bool CheckInputsFromMempoolAndCache(const CTransaction& tx, TxValidationS
423
410
  AssertLockHeld(cs_main);
424
411
  AssertLockHeld(pool.cs);
425
412
 
426
- assert(!tx.IsCoinBase());
413
+ assert(!tx.IsCoinBase() && !tx.IsCoinStake());
427
414
  for (const CTxIn& txin : tx.vin) {
428
415
  const Coin& coin = view.AccessCoin(txin.prevout);
429
416
 
@@ -598,9 +585,6 @@ private:
598
585
  // only tests that are fast should be done here (to avoid CPU DoS).
599
586
  bool PreChecks(ATMPArgs& args, Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
600
587
 
601
- // Run checks for mempool replace-by-fee.
602
- bool ReplacementChecks(Workspace& ws) EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
603
-
604
588
  // Enforce package mempool ancestor/descendant limits (distinct from individual
605
589
  // ancestor/descendant limits done in PreChecks).
606
590
  bool PackageMempoolChecks(const std::vector<CTransactionRef>& txns,
@@ -629,22 +613,6 @@ private:
629
613
  std::map<const uint256, const MempoolAcceptResult>& results)
630
614
  EXCLUSIVE_LOCKS_REQUIRED(cs_main, m_pool.cs);
631
615
 
632
- // Compare a package's feerate against minimum allowed.
633
- bool CheckFeeRate(size_t package_size, CAmount package_fee, TxValidationState& state) EXCLUSIVE_LOCKS_REQUIRED(::cs_main, m_pool.cs)
634
- {
635
- AssertLockHeld(::cs_main);
636
- AssertLockHeld(m_pool.cs);
637
- CAmount mempoolRejectFee = m_pool.GetMinFee(gArgs.GetIntArg("-maxmempool", DEFAULT_MAX_MEMPOOL_SIZE) * 1000000).GetFee(package_size);
638
- if (mempoolRejectFee > 0 && package_fee < mempoolRejectFee) {
639
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "mempool min fee not met", strprintf("%d < %d", package_fee, mempoolRejectFee));
640
- }
641
-
642
- if (package_fee < ::minRelayTxFee.GetFee(package_size)) {
643
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "min relay fee not met", strprintf("%d < %d", package_fee, ::minRelayTxFee.GetFee(package_size)));
644
- }
645
- return true;
646
- }
647
-
648
616
  private:
649
617
  CTxMemPool& m_pool;
650
618
  CCoinsViewCache m_view;
@@ -660,9 +628,6 @@ private:
660
628
  // in-mempool conflicts; see below).
661
629
  size_t m_limit_descendants;
662
630
  size_t m_limit_descendant_size;
663
-
664
- /** Whether the transaction(s) would replace any mempool transactions. If so, RBF rules apply. */
665
- bool m_rbf{false};
666
631
  };
667
632
 
668
633
  bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
@@ -675,7 +640,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
675
640
 
676
641
  // Copy/alias what we need out of args
677
642
  const int64_t nAcceptTime = args.m_accept_time;
678
- const bool bypass_limits = args.m_bypass_limits;
679
643
  std::vector<COutPoint>& coins_to_uncache = args.m_coins_to_uncache;
680
644
 
681
645
  // Alias what we need out of ws
@@ -685,9 +649,13 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
685
649
  if (!CheckTransaction(tx, state)) {
686
650
  return false; // state filled in by CheckTransaction
687
651
  }
652
+ // Time (prevent mempool memory exhaustion attack)
653
+ // moved from CheckTransaction() to here, because it makes no sense to make GetAdjustedTime() a part of the consensus rules - user can set his clock to whatever he wishes.
654
+ if (tx.nTime > GetAdjustedTime() + (IsProtocolV09(GetAdjustedTime()) ? MAX_FUTURE_BLOCK_TIME : MAX_FUTURE_BLOCK_TIME_PREV9))
655
+ return state.Invalid(TxValidationResult::TX_CONSENSUS, "timestamp-too-far");
688
656
 
689
657
  // Coinbase is only valid in a block, not as a loose transaction
690
- if (tx.IsCoinBase())
658
+ if (tx.IsCoinBase() || tx.IsCoinStake())
691
659
  return state.Invalid(TxValidationResult::TX_CONSENSUS, "coinbase");
692
660
 
693
661
  // Rather not work on nonstandard transactions (unless -testnet/-regtest)
@@ -722,25 +690,8 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
722
690
  {
723
691
  const CTransaction* ptxConflicting = m_pool.GetConflictTx(txin.prevout);
724
692
  if (ptxConflicting) {
725
- if (!args.m_allow_bip125_replacement) {
726
- // Transaction conflicts with a mempool tx, but we're not allowing replacements.
727
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "bip125-replacement-disallowed");
728
- }
729
- if (!ws.m_conflicts.count(ptxConflicting->GetHash()))
730
- {
731
- // Transactions that don't explicitly signal replaceability are
732
- // *not* replaceable with the current logic, even if one of their
733
- // unconfirmed ancestors signals replaceability. This diverges
734
- // from BIP125's inherited signaling description (see CVE-2021-31876).
735
- // Applications relying on first-seen mempool behavior should
736
- // check all unconfirmed ancestors; otherwise an opt-in ancestor
737
- // might be replaced, causing removal of this descendant.
738
- if (!SignalsOptInRBF(*ptxConflicting)) {
739
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "txn-mempool-conflict");
740
- }
741
-
742
- ws.m_conflicts.insert(ptxConflicting->GetHash());
743
- }
693
+ // Disable replacement feature for now
694
+ return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "txn-mempool-conflict");
744
695
  }
745
696
  }
746
697
 
@@ -790,10 +741,12 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
790
741
  return state.Invalid(TxValidationResult::TX_PREMATURE_SPEND, "non-BIP68-final");
791
742
 
792
743
  // The mempool holds txs for the next block, so pass height+1 to CheckTxInputs
793
- if (!Consensus::CheckTxInputs(tx, state, m_view, m_active_chainstate.m_chain.Height() + 1, ws.m_base_fees)) {
744
+ if (!Consensus::CheckTxInputs(tx, state, m_view, m_active_chainstate.m_chain.Height() + 1, ws.m_base_fees, Params().GetConsensus(), tx.nTime ? tx.nTime : GetAdjustedTime())) {
794
745
  return false; // state filled in by CheckTxInputs
795
746
  }
796
747
 
748
+ if (ws.m_base_fees < GetMinFee(tx, tx.nTime ? tx.nTime : GetAdjustedTime()))
749
+ return state.Invalid(TxValidationResult::TX_CONSENSUS, "fee is below minimum");
797
750
  // Check for non-standard pay-to-script-hash in inputs
798
751
  if (fRequireStandard && !AreInputsStandard(tx, m_view)) {
799
752
  return state.Invalid(TxValidationResult::TX_INPUTS_NOT_STANDARD, "bad-txns-nonstandard-inputs");
@@ -814,7 +767,7 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
814
767
  bool fSpendsCoinbase = false;
815
768
  for (const CTxIn &txin : tx.vin) {
816
769
  const Coin &coin = m_view.AccessCoin(txin.prevout);
817
- if (coin.IsCoinBase()) {
770
+ if (coin.IsCoinBase() || coin.IsCoinStake()) {
818
771
  fSpendsCoinbase = true;
819
772
  break;
820
773
  }
@@ -828,46 +781,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
828
781
  return state.Invalid(TxValidationResult::TX_NOT_STANDARD, "bad-txns-too-many-sigops",
829
782
  strprintf("%d", nSigOpsCost));
830
783
 
831
- // No transactions are allowed below minRelayTxFee except from disconnected
832
- // blocks
833
- if (!bypass_limits && !CheckFeeRate(ws.m_vsize, ws.m_modified_fees, state)) return false;
834
-
835
- ws.m_iters_conflicting = m_pool.GetIterSet(ws.m_conflicts);
836
- // Calculate in-mempool ancestors, up to a limit.
837
- if (ws.m_conflicts.size() == 1) {
838
- // In general, when we receive an RBF transaction with mempool conflicts, we want to know whether we
839
- // would meet the chain limits after the conflicts have been removed. However, there isn't a practical
840
- // way to do this short of calculating the ancestor and descendant sets with an overlay cache of
841
- // changed mempool entries. Due to both implementation and runtime complexity concerns, this isn't
842
- // very realistic, thus we only ensure a limited set of transactions are RBF'able despite mempool
843
- // conflicts here. Importantly, we need to ensure that some transactions which were accepted using
844
- // the below carve-out are able to be RBF'ed, without impacting the security the carve-out provides
845
- // for off-chain contract systems (see link in the comment below).
846
- //
847
- // Specifically, the subset of RBF transactions which we allow despite chain limits are those which
848
- // conflict directly with exactly one other transaction (but may evict children of said transaction),
849
- // and which are not adding any new mempool dependencies. Note that the "no new mempool dependencies"
850
- // check is accomplished later, so we don't bother doing anything about it here, but if BIP 125 is
851
- // amended, we may need to move that check to here instead of removing it wholesale.
852
- //
853
- // Such transactions are clearly not merging any existing packages, so we are only concerned with
854
- // ensuring that (a) no package is growing past the package size (not count) limits and (b) we are
855
- // not allowing something to effectively use the (below) carve-out spot when it shouldn't be allowed
856
- // to.
857
- //
858
- // To check these we first check if we meet the RBF criteria, above, and increment the descendant
859
- // limits by the direct conflict and its descendants (as these are recalculated in
860
- // CalculateMempoolAncestors by assuming the new transaction being added is a new descendant, with no
861
- // removals, of each parent's existing dependent set). The ancestor count limits are unmodified (as
862
- // the ancestor limits should be the same for both our new transaction and any conflicts).
863
- // We don't bother incrementing m_limit_descendants by the full removal count as that limit never comes
864
- // into force here (as we're only adding a single transaction).
865
- assert(ws.m_iters_conflicting.size() == 1);
866
- CTxMemPool::txiter conflict = *ws.m_iters_conflicting.begin();
867
-
868
- m_limit_descendants += 1;
869
- m_limit_descendant_size += conflict->GetSizeWithDescendants();
870
- }
871
784
 
872
785
  std::string errString;
873
786
  if (!m_pool.CalculateMemPoolAncestors(*entry, ws.m_ancestors, m_limit_ancestors, m_limit_ancestor_size, m_limit_descendants, m_limit_descendant_size, errString)) {
@@ -891,63 +804,6 @@ bool MemPoolAccept::PreChecks(ATMPArgs& args, Workspace& ws)
891
804
  }
892
805
  }
893
806
 
894
- // A transaction that spends outputs that would be replaced by it is invalid. Now
895
- // that we have the set of all ancestors we can detect this
896
- // pathological case by making sure ws.m_conflicts and ws.m_ancestors don't
897
- // intersect.
898
- if (const auto err_string{EntriesAndTxidsDisjoint(ws.m_ancestors, ws.m_conflicts, hash)}) {
899
- // We classify this as a consensus error because a transaction depending on something it
900
- // conflicts with would be inconsistent.
901
- return state.Invalid(TxValidationResult::TX_CONSENSUS, "bad-txns-spends-conflicting-tx", *err_string);
902
- }
903
-
904
- m_rbf = !ws.m_conflicts.empty();
905
- return true;
906
- }
907
-
908
- bool MemPoolAccept::ReplacementChecks(Workspace& ws)
909
- {
910
- AssertLockHeld(cs_main);
911
- AssertLockHeld(m_pool.cs);
912
-
913
- const CTransaction& tx = *ws.m_ptx;
914
- const uint256& hash = ws.m_hash;
915
- TxValidationState& state = ws.m_state;
916
-
917
- CFeeRate newFeeRate(ws.m_modified_fees, ws.m_vsize);
918
- // The replacement transaction must have a higher feerate than its direct conflicts.
919
- // - The motivation for this check is to ensure that the replacement transaction is preferable for
920
- // block-inclusion, compared to what would be removed from the mempool.
921
- // - This logic predates ancestor feerate-based transaction selection, which is why it doesn't
922
- // consider feerates of descendants.
923
- // - Note: Ancestor feerate-based transaction selection has made this comparison insufficient to
924
- // guarantee that this is incentive-compatible for miners, because it is possible for a
925
- // descendant transaction of a direct conflict to pay a higher feerate than the transaction that
926
- // might replace them, under these rules.
927
- if (const auto err_string{PaysMoreThanConflicts(ws.m_iters_conflicting, newFeeRate, hash)}) {
928
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee", *err_string);
929
- }
930
-
931
- // Calculate all conflicting entries and enforce BIP125 Rule #5.
932
- if (const auto err_string{GetEntriesForConflicts(tx, m_pool, ws.m_iters_conflicting, ws.m_all_conflicting)}) {
933
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY,
934
- "too many potential replacements", *err_string);
935
- }
936
- // Enforce BIP125 Rule #2.
937
- if (const auto err_string{HasNoNewUnconfirmed(tx, m_pool, ws.m_iters_conflicting)}) {
938
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY,
939
- "replacement-adds-unconfirmed", *err_string);
940
- }
941
- // Check if it's economically rational to mine this transaction rather than the ones it
942
- // replaces and pays for its own relay fees. Enforce BIP125 Rules #3 and #4.
943
- for (CTxMemPool::txiter it : ws.m_all_conflicting) {
944
- ws.m_conflicting_fees += it->GetModifiedFee();
945
- ws.m_conflicting_size += it->GetTxSize();
946
- }
947
- if (const auto err_string{PaysForRBF(ws.m_conflicting_fees, ws.m_modified_fees, ws.m_vsize,
948
- ::incrementalRelayFee, hash)}) {
949
- return state.Invalid(TxValidationResult::TX_MEMPOOL_POLICY, "insufficient fee", *err_string);
950
- }
951
807
  return true;
952
808
  }
953
809
 
@@ -977,7 +833,16 @@ bool MemPoolAccept::PolicyScriptChecks(const ATMPArgs& args, Workspace& ws)
977
833
  const CTransaction& tx = *ws.m_ptx;
978
834
  TxValidationState& state = ws.m_state;
979
835
 
980
- constexpr unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
836
+ unsigned int scriptVerifyFlags = STANDARD_SCRIPT_VERIFY_FLAGS;
837
+
838
+ // peercoin: if transaction is after version 0.8 fork, verify SCRIPT_VERIFY_LOW_S
839
+ // ppcTODO move back to policy.h after 0.8 is active
840
+ //if (IsBTC16BIPsEnabled(tx.nTime))
841
+ // scriptVerifyFlags &= SCRIPT_VERIFY_LOW_S;
842
+
843
+ // peercoin allow taproot after fork
844
+ //if (IsProtocolV12(tx.nTime))
845
+ // scriptVerifyFlags &= SCRIPT_VERIFY_TAPROOT;
981
846
 
982
847
  // Check input scripts and signatures.
983
848
  // This is done last to help prevent CPU exhaustion denial-of-service attacks.
@@ -1036,35 +901,14 @@ bool MemPoolAccept::Finalize(const ATMPArgs& args, Workspace& ws)
1036
901
  {
1037
902
  AssertLockHeld(cs_main);
1038
903
  AssertLockHeld(m_pool.cs);
1039
- const CTransaction& tx = *ws.m_ptx;
1040
904
  const uint256& hash = ws.m_hash;
1041
905
  TxValidationState& state = ws.m_state;
1042
906
  const bool bypass_limits = args.m_bypass_limits;
1043
907
 
1044
908
  std::unique_ptr<CTxMemPoolEntry>& entry = ws.m_entry;
1045
909
 
1046
- // Remove conflicting transactions from the mempool
1047
- for (CTxMemPool::txiter it : ws.m_all_conflicting)
1048
- {
1049
- LogPrint(BCLog::MEMPOOL, "replacing tx %s with %s for %s additional fees, %d delta bytes\n",
1050
- it->GetTx().GetHash().ToString(),
1051
- hash.ToString(),
1052
- FormatMoney(ws.m_modified_fees - ws.m_conflicting_fees),
1053
- (int)entry->GetTxSize() - (int)ws.m_conflicting_size);
1054
- ws.m_replaced_transactions.push_back(it->GetSharedTx());
1055
- }
1056
- m_pool.RemoveStaged(ws.m_all_conflicting, false, MemPoolRemovalReason::REPLACED);
1057
-
1058
- // This transaction should only count for fee estimation if:
1059
- // - it's not being re-added during a reorg which bypasses typical mempool fee limits
1060
- // - the node is not behind
1061
- // - the transaction is not dependent on any other transactions in the mempool
1062
- // - it's not part of a package. Since package relay is not currently supported, this
1063
- // transaction has not necessarily been accepted to miners' mempools.
1064
- bool validForFeeEstimation = !bypass_limits && !args.m_package_submission && IsCurrentForFeeEstimation(m_active_chainstate) && m_pool.HasNoInputsOf(tx);
1065
-
1066
910
  // Store transaction in memory
1067
- m_pool.addUnchecked(*entry, ws.m_ancestors, validForFeeEstimation);
911
+ m_pool.addUnchecked(*entry, ws.m_ancestors);
1068
912
 
1069
913
  // trim mempool and check if tx was trimmed
1070
914
  // If we are validating a package, don't trim here because we could evict a previous transaction
@@ -1162,8 +1006,6 @@ MempoolAcceptResult MemPoolAccept::AcceptSingleTransaction(const CTransactionRef
1162
1006
 
1163
1007
  if (!PreChecks(args, ws)) return MempoolAcceptResult::Failure(ws.m_state);
1164
1008
 
1165
- if (m_rbf && !ReplacementChecks(ws)) return MempoolAcceptResult::Failure(ws.m_state);
1166
-
1167
1009
  // Perform the inexpensive checks first and avoid hashing and signature verification unless
1168
1010
  // those checks pass, to mitigate CPU exhaustion denial-of-service attacks.
1169
1011
  if (!PolicyScriptChecks(args, ws)) return MempoolAcceptResult::Failure(ws.m_state);
@@ -1414,16 +1256,67 @@ PackageMempoolAcceptResult ProcessNewPackage(CChainState& active_chainstate, CTx
1414
1256
  return result;
1415
1257
  }
1416
1258
 
1417
- CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams)
1259
+ int64_t GetProofOfWorkReward(unsigned int nBits, uint32_t nTime)
1418
1260
  {
1419
- int halvings = nHeight / consensusParams.nSubsidyHalvingInterval;
1420
- // Force block reward to zero when right shift is undefined.
1421
- if (halvings >= 64)
1422
- return 0;
1423
-
1424
- CAmount nSubsidy = 50 * COIN;
1425
- // Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years.
1426
- nSubsidy >>= halvings;
1261
+ CBigNum bnSubsidyLimit = MAX_MINT_PROOF_OF_WORK;
1262
+ CBigNum bnTarget;
1263
+ bnTarget.SetCompact(nBits);
1264
+ CBigNum bnTargetLimit(Params().GetConsensus().powLimit);
1265
+ bnTargetLimit.SetCompact(bnTargetLimit.GetCompact());
1266
+
1267
+ // peercoin: subsidy is cut in half every 16x multiply of difficulty
1268
+ // A reasonably continuous curve is used to avoid shock to market
1269
+ // (nSubsidyLimit / nSubsidy) ** 4 == bnProofOfWorkLimit / bnTarget
1270
+ CBigNum bnLowerBound = CENT;
1271
+ CBigNum bnUpperBound = bnSubsidyLimit;
1272
+ while (bnLowerBound + CENT <= bnUpperBound)
1273
+ {
1274
+ CBigNum bnMidValue = (bnLowerBound + bnUpperBound) / 2;
1275
+ if (gArgs.GetBoolArg("-printcreation", false))
1276
+ LogPrintf("%s: lower=%lld upper=%lld mid=%lld\n", __func__, bnLowerBound.getuint64(), bnUpperBound.getuint64(), bnMidValue.getuint64());
1277
+ if (bnMidValue * bnMidValue * bnMidValue * bnMidValue * bnTargetLimit > bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnSubsidyLimit * bnTarget)
1278
+ bnUpperBound = bnMidValue;
1279
+ else
1280
+ bnLowerBound = bnMidValue;
1281
+ }
1282
+
1283
+ int64_t nSubsidy = bnUpperBound.getuint64();
1284
+ nSubsidy = (nSubsidy / CENT) * CENT;
1285
+
1286
+ nSubsidy = std::min(nSubsidy, IsProtocolV10(nTime) ? MAX_MINT_PROOF_OF_WORK_V10 : MAX_MINT_PROOF_OF_WORK);
1287
+
1288
+ if (gArgs.GetBoolArg("-printcreation", false))
1289
+ LogPrintf("%s: create=%s nBits=0x%08x nSubsidy=%lld\n", __func__, FormatMoney(nSubsidy), nBits, nSubsidy);
1290
+
1291
+ return nSubsidy;
1292
+ }
1293
+
1294
+ // peercoin: miner's coin stake is rewarded based on coin age spent (coin-days)
1295
+ int64_t GetProofOfStakeReward(int64_t nCoinAge, uint32_t nTime, uint64_t nMoneySupply)
1296
+ {
1297
+ static int64_t nRewardCoinYear = CENT; // creation amount per coin-year
1298
+ int64_t nSubsidy = nCoinAge * 33 / (365 * 33 + 8) * nRewardCoinYear;
1299
+
1300
+ if (IsProtocolV09(nTime)) {
1301
+ // rfc18
1302
+ // YearlyBlocks = ((365 * 33 + 8) / 33) * 1440 / 10
1303
+ // some efforts not to lose precision
1304
+ CBigNum bnInflationAdjustment = nMoneySupply;
1305
+ bnInflationAdjustment *= 25 * 33;
1306
+ bnInflationAdjustment /= 10000 * 144;
1307
+ bnInflationAdjustment /= (365 * 33 + 8);
1308
+
1309
+ uint64_t nInflationAdjustment = bnInflationAdjustment.getuint64();
1310
+ uint64_t nSubsidyNew = (nSubsidy * 3) + nInflationAdjustment;
1311
+
1312
+ if (gArgs.GetBoolArg("-printcreation", false))
1313
+ LogPrintf("%s: money supply %ld, inflation adjustment %f, old subsidy %ld, new subsidy %ld\n", __func__, nMoneySupply, nInflationAdjustment/1000000.0, nSubsidy, nSubsidyNew);
1314
+
1315
+ nSubsidy = nSubsidyNew;
1316
+ }
1317
+
1318
+ if (gArgs.GetBoolArg("-printcreation", false))
1319
+ LogPrintf("%s: create=%s nCoinAge=%lld\n", __func__, FormatMoney(nSubsidy), nCoinAge);
1427
1320
  return nSubsidy;
1428
1321
  }
1429
1322
 
@@ -1492,7 +1385,7 @@ bool CChainState::IsInitialBlockDownload() const
1492
1385
  return true;
1493
1386
  if (m_chain.Tip() == nullptr)
1494
1387
  return true;
1495
- if (m_chain.Tip()->nChainWork < nMinimumChainWork)
1388
+ if (m_chain.Tip()->nChainTrust < nMinimumChainWork)
1496
1389
  return true;
1497
1390
  if (m_chain.Tip()->GetBlockTime() < (GetTime() - nMaxTipAge))
1498
1391
  return true;
@@ -1501,9 +1394,11 @@ bool CChainState::IsInitialBlockDownload() const
1501
1394
  return false;
1502
1395
  }
1503
1396
 
1504
- static void AlertNotify(const std::string& strMessage)
1397
+
1398
+ void AlertNotify(const std::string& strMessage, bool fUpdateUI)
1505
1399
  {
1506
- uiInterface.NotifyAlertChanged();
1400
+ if (fUpdateUI)
1401
+ uiInterface.NotifyAlertChanged(uint256(), CT_UPDATED); // peercoin: we are using arguments that will have no effects in updateAlert()
1507
1402
  #if HAVE_SYSTEM
1508
1403
  std::string strCmd = gArgs.GetArg("-alertnotify", "");
1509
1404
  if (strCmd.empty()) return;
@@ -1531,7 +1426,7 @@ void CChainState::CheckForkWarningConditions()
1531
1426
  return;
1532
1427
  }
1533
1428
 
1534
- if (m_chainman.m_best_invalid && m_chainman.m_best_invalid->nChainWork > m_chain.Tip()->nChainWork + (GetBlockProof(*m_chain.Tip()) * 6)) {
1429
+ if (m_chainman.m_best_invalid && m_chainman.m_best_invalid->nChainTrust > m_chain.Tip()->nChainTrust + (GetBlockTrust(*m_chain.Tip()) * 6)) {
1535
1430
  LogPrintf("%s: Warning: Found invalid chain at least ~6 blocks longer than our best chain.\nChain state database corruption likely.\n", __func__);
1536
1431
  SetfLargeWorkInvalidChainFound(true);
1537
1432
  } else {
@@ -1543,21 +1438,25 @@ void CChainState::CheckForkWarningConditions()
1543
1438
  void CChainState::InvalidChainFound(CBlockIndex* pindexNew)
1544
1439
  {
1545
1440
  AssertLockHeld(cs_main);
1546
- if (!m_chainman.m_best_invalid || pindexNew->nChainWork > m_chainman.m_best_invalid->nChainWork) {
1441
+ if (!m_chainman.m_best_invalid || pindexNew->nChainTrust > m_chainman.m_best_invalid->nChainTrust) {
1547
1442
  m_chainman.m_best_invalid = pindexNew;
1548
1443
  }
1549
1444
  if (pindexBestHeader != nullptr && pindexBestHeader->GetAncestor(pindexNew->nHeight) == pindexNew) {
1550
1445
  pindexBestHeader = m_chain.Tip();
1551
1446
  }
1552
1447
 
1553
- LogPrintf("%s: invalid block=%s height=%d log2_work=%f date=%s\n", __func__,
1448
+ LogPrintf("%s: invalid block=%s height=%d log2_trust=%.8g moneysupply=%s date=%s moneysupply=%s\n", __func__,
1554
1449
  pindexNew->GetBlockHash().ToString(), pindexNew->nHeight,
1555
- log(pindexNew->nChainWork.getdouble())/log(2.0), FormatISO8601DateTime(pindexNew->GetBlockTime()));
1450
+ log(pindexNew->nChainTrust.getdouble())/log(2.0),
1451
+ FormatMoney(m_chain.Tip()->nMoneySupply),
1452
+ FormatISO8601DateTime(pindexNew->GetBlockTime()),
1453
+ FormatMoney(pindexNew->nMoneySupply));
1556
1454
  CBlockIndex *tip = m_chain.Tip();
1557
1455
  assert (tip);
1558
- LogPrintf("%s: current best=%s height=%d log2_work=%f date=%s\n", __func__,
1559
- tip->GetBlockHash().ToString(), m_chain.Height(), log(tip->nChainWork.getdouble())/log(2.0),
1560
- FormatISO8601DateTime(tip->GetBlockTime()));
1456
+ LogPrintf("%s: current best=%s height=%d log2_trust=%.8g moneysupply=%s date=%s moneysupply=%s\n", __func__,
1457
+ tip->GetBlockHash().ToString(), m_chain.Height(), log(tip->nChainTrust.getdouble())/log(2.0),
1458
+ FormatMoney(tip->nMoneySupply),
1459
+ FormatISO8601DateTime(tip->GetBlockTime()), FormatMoney(pindexNew->nMoneySupply));
1561
1460
  CheckForkWarningConditions();
1562
1461
  }
1563
1462
 
@@ -1575,7 +1474,7 @@ void CChainState::InvalidBlockFound(CBlockIndex* pindex, const BlockValidationSt
1575
1474
  }
1576
1475
  }
1577
1476
 
1578
- void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight)
1477
+ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txundo, int nHeight, bool skipZeroValue)
1579
1478
  {
1580
1479
  // mark inputs spent
1581
1480
  if (!tx.IsCoinBase()) {
@@ -1587,7 +1486,7 @@ void UpdateCoins(const CTransaction& tx, CCoinsViewCache& inputs, CTxUndo &txund
1587
1486
  }
1588
1487
  }
1589
1488
  // add outputs
1590
- AddCoins(inputs, tx, nHeight);
1489
+ AddCoins(inputs, tx, nHeight, false, skipZeroValue);
1591
1490
  }
1592
1491
 
1593
1492
  bool CScriptCheck::operator()() {
@@ -1749,6 +1648,8 @@ int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out)
1749
1648
  if (!alternate.IsSpent()) {
1750
1649
  undo.nHeight = alternate.nHeight;
1751
1650
  undo.fCoinBase = alternate.fCoinBase;
1651
+ undo.fCoinStake = alternate.fCoinStake; // peercoin
1652
+ undo.nTime = alternate.nTime; // peercoin
1752
1653
  } else {
1753
1654
  return DISCONNECT_FAILED; // adding output for transaction without known metadata
1754
1655
  }
@@ -1758,7 +1659,7 @@ int ApplyTxInUndo(Coin&& undo, CCoinsViewCache& view, const COutPoint& out)
1758
1659
  // already checked whether an unspent coin exists above using HaveCoin, so
1759
1660
  // we don't need to guess. When fClean is false, an unspent coin already
1760
1661
  // existed and it is an overwrite.
1761
- view.AddCoin(out, std::move(undo), !fClean);
1662
+ view.AddCoin(out, std::move(undo), !fClean, false);
1762
1663
 
1763
1664
  return fClean ? DISCONNECT_OK : DISCONNECT_UNCLEAN;
1764
1665
  }
@@ -1786,15 +1687,18 @@ DisconnectResult CChainState::DisconnectBlock(const CBlock& block, const CBlockI
1786
1687
  const CTransaction &tx = *(block.vtx[i]);
1787
1688
  uint256 hash = tx.GetHash();
1788
1689
  bool is_coinbase = tx.IsCoinBase();
1690
+ bool is_coinstake = tx.IsCoinStake();
1789
1691
 
1790
1692
  // Check that all outputs are available and match the outputs in the block itself
1791
1693
  // exactly.
1792
1694
  for (size_t o = 0; o < tx.vout.size(); o++) {
1793
1695
  if (!tx.vout[o].scriptPubKey.IsUnspendable()) {
1696
+ if (IsProtocolV12(pindex) && !tx.vout[o].nValue)
1697
+ continue;
1794
1698
  COutPoint out(hash, o);
1795
1699
  Coin coin;
1796
1700
  bool is_spent = view.SpendCoin(out, &coin);
1797
- if (!is_spent || tx.vout[o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.fCoinBase) {
1701
+ if (!is_spent || tx.vout[o] != coin.out || pindex->nHeight != coin.nHeight || is_coinbase != coin.fCoinBase || is_coinstake != coin.fCoinStake) {
1798
1702
  fClean = false; // transaction output mismatch
1799
1703
  }
1800
1704
  }
@@ -1836,33 +1740,6 @@ void StopScriptCheckWorkerThreads()
1836
1740
  scriptcheckqueue.StopWorkerThreads();
1837
1741
  }
1838
1742
 
1839
- /**
1840
- * Threshold condition checker that triggers when unknown versionbits are seen on the network.
1841
- */
1842
- class WarningBitsConditionChecker : public AbstractThresholdConditionChecker
1843
- {
1844
- private:
1845
- int bit;
1846
-
1847
- public:
1848
- explicit WarningBitsConditionChecker(int bitIn) : bit(bitIn) {}
1849
-
1850
- int64_t BeginTime(const Consensus::Params& params) const override { return 0; }
1851
- int64_t EndTime(const Consensus::Params& params) const override { return std::numeric_limits<int64_t>::max(); }
1852
- int Period(const Consensus::Params& params) const override { return params.nMinerConfirmationWindow; }
1853
- int Threshold(const Consensus::Params& params) const override { return params.nRuleChangeActivationThreshold; }
1854
-
1855
- bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override
1856
- {
1857
- return pindex->nHeight >= params.MinBIP9WarningHeight &&
1858
- ((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) &&
1859
- ((pindex->nVersion >> bit) & 1) != 0 &&
1860
- ((g_versionbitscache.ComputeBlockVersion(pindex->pprev, params) >> bit) & 1) == 0;
1861
- }
1862
- };
1863
-
1864
- static ThresholdConditionCache warningcache[VERSIONBITS_NUM_BITS] GUARDED_BY(cs_main);
1865
-
1866
1743
  static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consensus::Params& consensusparams)
1867
1744
  {
1868
1745
  unsigned int flags = SCRIPT_VERIFY_NONE;
@@ -1881,30 +1758,26 @@ static unsigned int GetBlockScriptFlags(const CBlockIndex* pindex, const Consens
1881
1758
  }
1882
1759
 
1883
1760
  // Enforce the DERSIG (BIP66) rule
1884
- if (DeploymentActiveAt(*pindex, consensusparams, Consensus::DEPLOYMENT_DERSIG)) {
1761
+ if (pindex->pprev && IsBTC16BIPsEnabled(pindex->pprev->nTime)) {
1885
1762
  flags |= SCRIPT_VERIFY_DERSIG;
1886
1763
  }
1887
1764
 
1888
1765
  // Enforce CHECKLOCKTIMEVERIFY (BIP65)
1889
- if (DeploymentActiveAt(*pindex, consensusparams, Consensus::DEPLOYMENT_CLTV)) {
1766
+ if (IsProtocolV06(pindex->pprev)) {
1890
1767
  flags |= SCRIPT_VERIFY_CHECKLOCKTIMEVERIFY;
1891
1768
  }
1892
1769
 
1893
- // Enforce CHECKSEQUENCEVERIFY (BIP112)
1894
- if (DeploymentActiveAt(*pindex, consensusparams, Consensus::DEPLOYMENT_CSV)) {
1895
- flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY;
1770
+ // Enforce BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY)
1771
+ // Enforce BIP147 NULLDUMMY (activated simultaneously with segwit)
1772
+ if (pindex->pprev && IsBTC16BIPsEnabled(pindex->pprev->nTime)) {
1773
+ flags |= SCRIPT_VERIFY_CHECKSEQUENCEVERIFY | SCRIPT_VERIFY_NULLDUMMY;
1896
1774
  }
1897
1775
 
1898
1776
  // Enforce Taproot (BIP340-BIP342)
1899
- if (DeploymentActiveAt(*pindex, consensusparams, Consensus::DEPLOYMENT_TAPROOT)) {
1777
+ if (pindex->pprev && IsProtocolV12(pindex->pprev)) {
1900
1778
  flags |= SCRIPT_VERIFY_TAPROOT;
1901
1779
  }
1902
1780
 
1903
- // Enforce BIP147 NULLDUMMY (activated simultaneously with segwit)
1904
- if (DeploymentActiveAt(*pindex, consensusparams, Consensus::DEPLOYMENT_SEGWIT)) {
1905
- flags |= SCRIPT_VERIFY_NULLDUMMY;
1906
- }
1907
-
1908
1781
  return flags;
1909
1782
  }
1910
1783
 
@@ -1918,6 +1791,80 @@ static int64_t nTimeIndex = 0;
1918
1791
  static int64_t nTimeTotal = 0;
1919
1792
  static int64_t nBlocksTotal = 0;
1920
1793
 
1794
+ // These checks can only be done when all previous block have been added.
1795
+ bool PeercoinContextualBlockChecks(const CBlock& block, BlockValidationState& state, CBlockIndex* pindex, bool fJustCheck, CChainState& chainstate)
1796
+ {
1797
+ uint256 hashProofOfStake = uint256();
1798
+ // peercoin: verify hash target and signature of coinstake tx
1799
+ if (block.IsProofOfStake() && !CheckProofOfStake(state, pindex->pprev, block.vtx[1], block.nBits, hashProofOfStake, block.vtx[1]->nTime ? block.vtx[1]->nTime : block.nTime, chainstate)) {
1800
+ LogPrintf("WARNING: %s: check proof-of-stake failed for block %s\n", __func__, block.GetHash().ToString());
1801
+ return false; // do not error here as we expect this during initial block download
1802
+ }
1803
+
1804
+ // peercoin: check for duplicity of stake
1805
+ if (block.IsProofOfStake()) {
1806
+ std::pair<COutPoint, unsigned int> proofOfStake = block.GetProofOfStake();
1807
+ if (pindex->IsProofOfStake() && proofOfStake.first == pindex->prevoutStake) {
1808
+ LogPrintf("WARNING: %s: duplicate proof-of-stake in block %s, invalidating tip\n", __func__, block.GetHash().ToString());
1809
+ chainstate.InvalidateBlock(state, pindex);
1810
+ return error("ConnectBlock() : Duplicate coinstake found");
1811
+ } else if (setStakeSeen.count(proofOfStake)) {
1812
+ LogPrintf("WARNING: %s: duplicate proof-of-stake in block %s\n", __func__, block.GetHash().ToString());
1813
+ return error("ConnectBlock() : Duplicate coinstake found");
1814
+ }
1815
+ }
1816
+
1817
+ // peercoin: compute stake entropy bit for stake modifier
1818
+ unsigned int nEntropyBit = GetStakeEntropyBit(block);
1819
+
1820
+ // peercoin: compute stake modifier
1821
+ uint64_t nStakeModifier = 0;
1822
+ bool fGeneratedStakeModifier = false;
1823
+ if (!ComputeNextStakeModifier(pindex, nStakeModifier, fGeneratedStakeModifier, chainstate))
1824
+ return error("ConnectBlock() : ComputeNextStakeModifier() failed");
1825
+
1826
+ // compute nStakeModifierChecksum begin
1827
+ unsigned int nFlagsBackup = pindex->nFlags;
1828
+ uint64_t nStakeModifierBackup = pindex->nStakeModifier;
1829
+ uint256 hashProofOfStakeBackup = pindex->hashProofOfStake;
1830
+
1831
+ // set necessary pindex fields
1832
+ if (!pindex->SetStakeEntropyBit(nEntropyBit))
1833
+ return error("ConnectBlock() : SetStakeEntropyBit() failed");
1834
+ pindex->SetStakeModifier(nStakeModifier, fGeneratedStakeModifier);
1835
+ pindex->hashProofOfStake = hashProofOfStake;
1836
+
1837
+ unsigned int nStakeModifierChecksum = GetStakeModifierChecksum(pindex);
1838
+
1839
+ // undo pindex fields
1840
+ pindex->nFlags = nFlagsBackup;
1841
+ pindex->nStakeModifier = nStakeModifierBackup;
1842
+ pindex->hashProofOfStake = hashProofOfStakeBackup;
1843
+ // compute nStakeModifierChecksum end
1844
+
1845
+ if (!CheckStakeModifierCheckpoints(pindex->nHeight, nStakeModifierChecksum))
1846
+ return error("ConnectBlock() : Rejected by stake modifier checkpoint height=%d, modifier=0x%016llx", pindex->nHeight, nStakeModifier);
1847
+
1848
+ if (fJustCheck)
1849
+ return true;
1850
+
1851
+ // write everything to index
1852
+ if (block.IsProofOfStake())
1853
+ {
1854
+ pindex->prevoutStake = block.vtx[1]->vin[0].prevout;
1855
+ pindex->nStakeTime = block.vtx[1]->nTime;
1856
+ pindex->hashProofOfStake = hashProofOfStake;
1857
+ setStakeSeen.insert(std::make_pair(pindex->prevoutStake, pindex->nTime));
1858
+ }
1859
+ if (!pindex->SetStakeEntropyBit(nEntropyBit))
1860
+ return error("ConnectBlock() : SetStakeEntropyBit() failed");
1861
+ pindex->SetStakeModifier(nStakeModifier, fGeneratedStakeModifier);
1862
+ pindex->nStakeModifierChecksum = nStakeModifierChecksum;
1863
+ chainstate.m_blockman.m_dirty_blockindex.insert(pindex); // queue a write to disk
1864
+
1865
+ return true;
1866
+ }
1867
+
1921
1868
  /** Apply the effects of this block (with given index) on the UTXO set represented by coins.
1922
1869
  * Validity checks that depend on the UTXO set are also done; ConnectBlock()
1923
1870
  * can fail if those validity checks fail (among other reasons). */
@@ -1932,6 +1879,9 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
1932
1879
 
1933
1880
  int64_t nTimeStart = GetTimeMicros();
1934
1881
 
1882
+ if (pindex->nStakeModifier == 0 && pindex->nStakeModifierChecksum == 0 && !PeercoinContextualBlockChecks(block, state, pindex, fJustCheck, m_chainman.ActiveChainstate()))
1883
+ return error("%s: failed PoS check %s", __func__, state.ToString());
1884
+
1935
1885
  // Check it again in case a previous version let a bad block in
1936
1886
  // NOTE: We don't currently (re-)invoke ContextualCheckBlock() or
1937
1887
  // ContextualCheckBlockHeader() here. This means that if we add a new
@@ -1980,7 +1930,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
1980
1930
  if (it != m_blockman.m_block_index.end()) {
1981
1931
  if (it->second->GetAncestor(pindex->nHeight) == pindex &&
1982
1932
  pindexBestHeader->GetAncestor(pindex->nHeight) == pindex &&
1983
- pindexBestHeader->nChainWork >= nMinimumChainWork) {
1933
+ pindexBestHeader->nChainTrust >= nMinimumChainWork) {
1984
1934
  // This block is a member of the assumed verified chain and an ancestor of the best header.
1985
1935
  // Script verification is skipped when connecting blocks under the
1986
1936
  // assumevalid block. Assuming the assumevalid block is valid this
@@ -2013,8 +1963,7 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
2013
1963
  // Now that the whole chain is irreversibly beyond that time it is applied to all blocks except the
2014
1964
  // two in the chain that violate it. This prevents exploiting the issue against nodes during their
2015
1965
  // initial block download.
2016
- bool fEnforceBIP30 = !((pindex->nHeight==91842 && pindex->GetBlockHash() == uint256S("0x00000000000a4d0a398161ffc163c503763b1f4360639393e0e4c8e300e0caec")) ||
2017
- (pindex->nHeight==91880 && pindex->GetBlockHash() == uint256S("0x00000000000743f190a18c5577a3c2d2a1f610ae9601ac046a38084ccb7cd721")));
1966
+ bool fEnforceBIP30 = (!pindex->phashBlock); // Enforce on CreateNewBlock invocations which don't have a hash.
2018
1967
 
2019
1968
  // Once BIP34 activated it was not possible to create new duplicate coinbases and thus other than starting
2020
1969
  // with the 2 existing duplicate coinbase pairs, not possible to create overwriting txs. But by the
@@ -2090,9 +2039,9 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
2090
2039
  }
2091
2040
  }
2092
2041
 
2093
- // Enforce BIP68 (sequence locks)
2042
+ // Enforce BIP68 (sequence locks) and BIP112 (CHECKSEQUENCEVERIFY)
2094
2043
  int nLockTimeFlags = 0;
2095
- if (DeploymentActiveAt(*pindex, m_params.GetConsensus(), Consensus::DEPLOYMENT_CSV)) {
2044
+ if (pindex->pprev && IsBTC16BIPsEnabled(pindex->pprev->nTime)) {
2096
2045
  nLockTimeFlags |= LOCKTIME_VERIFY_SEQUENCE;
2097
2046
  }
2098
2047
 
@@ -2114,6 +2063,8 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
2114
2063
 
2115
2064
  std::vector<int> prevheights;
2116
2065
  CAmount nFees = 0;
2066
+ int64_t nValueIn = 0;
2067
+ int64_t nValueOut = 0;
2117
2068
  int nInputs = 0;
2118
2069
  int64_t nSigOpsCost = 0;
2119
2070
  blockundo.vtxundo.reserve(block.vtx.size() - 1);
@@ -2123,17 +2074,23 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
2123
2074
 
2124
2075
  nInputs += tx.vin.size();
2125
2076
 
2126
- if (!tx.IsCoinBase())
2077
+ if (tx.IsCoinBase())
2078
+ nValueOut += tx.GetValueOut();
2079
+ else
2127
2080
  {
2128
2081
  CAmount txfee = 0;
2129
2082
  TxValidationState tx_state;
2130
- if (!Consensus::CheckTxInputs(tx, tx_state, view, pindex->nHeight, txfee)) {
2083
+ if (!Consensus::CheckTxInputs(tx, tx_state, view, pindex->nHeight, txfee, Params().GetConsensus(), tx.nTime ? tx.nTime : block.nTime, (pindex->pprev? pindex->pprev->nMoneySupply : 0))) {
2131
2084
  // Any transaction validation failure in ConnectBlock is a block consensus failure
2132
2085
  state.Invalid(BlockValidationResult::BLOCK_CONSENSUS,
2133
2086
  tx_state.GetRejectReason(), tx_state.GetDebugMessage());
2134
2087
  return error("%s: Consensus::CheckTxInputs: %s, %s", __func__, tx.GetHash().ToString(), state.ToString());
2135
2088
  }
2136
- nFees += txfee;
2089
+ for (unsigned int i = 0; i < tx.vin.size(); i++)
2090
+ nValueIn += view.AccessCoin(tx.vin[i].prevout).out.nValue;
2091
+ nValueOut += tx.GetValueOut();
2092
+ if (!tx.IsCoinStake())
2093
+ nFees += txfee;
2137
2094
  if (!MoneyRange(nFees)) {
2138
2095
  LogPrintf("ERROR: %s: accumulated fee in the block out of range.\n", __func__);
2139
2096
  return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-txns-accumulated-fee-outofrange");
@@ -2182,16 +2139,12 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
2182
2139
  if (i > 0) {
2183
2140
  blockundo.vtxundo.push_back(CTxUndo());
2184
2141
  }
2185
- UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight);
2142
+ UpdateCoins(tx, view, i == 0 ? undoDummy : blockundo.vtxundo.back(), pindex->nHeight, IsProtocolV12(pindex));
2186
2143
  }
2187
2144
  int64_t nTime3 = GetTimeMicros(); nTimeConnect += nTime3 - nTime2;
2188
2145
  LogPrint(BCLog::BENCH, " - Connect %u transactions: %.2fms (%.3fms/tx, %.3fms/txin) [%.2fs (%.2fms/blk)]\n", (unsigned)block.vtx.size(), MILLI * (nTime3 - nTime2), MILLI * (nTime3 - nTime2) / block.vtx.size(), nInputs <= 1 ? 0 : MILLI * (nTime3 - nTime2) / (nInputs-1), nTimeConnect * MICRO, nTimeConnect * MILLI / nBlocksTotal);
2189
2146
 
2190
- CAmount blockReward = nFees + GetBlockSubsidy(pindex->nHeight, m_params.GetConsensus());
2191
- if (block.vtx[0]->GetValueOut() > blockReward) {
2192
- LogPrintf("ERROR: ConnectBlock(): coinbase pays too much (actual=%d vs limit=%d)\n", block.vtx[0]->GetValueOut(), blockReward);
2193
- return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-amount");
2194
- }
2147
+ // peercoin: coinbase reward check relocated to CheckBlock()
2195
2148
 
2196
2149
  if (!control.Wait()) {
2197
2150
  LogPrintf("ERROR: %s: CheckQueue failed\n", __func__);
@@ -2203,6 +2156,15 @@ bool CChainState::ConnectBlock(const CBlock& block, BlockValidationState& state,
2203
2156
  if (fJustCheck)
2204
2157
  return true;
2205
2158
 
2159
+ // peercoin: track money supply and mint amount info
2160
+ pindex->nMint = nValueOut - nValueIn + nFees;
2161
+ pindex->nMoneySupply = (pindex->pprev? pindex->pprev->nMoneySupply : 0) + nValueOut - nValueIn;
2162
+
2163
+ // peercoin: fees are not collected by miners as in bitcoin
2164
+ // peercoin: fees are destroyed to compensate the entire network
2165
+ if (gArgs.GetBoolArg("-printcreation", false))
2166
+ LogPrintf("%s: destroy=%s nFees=%lld\n", __func__, FormatMoney(nFees), nFees);
2167
+
2206
2168
  if (!m_blockman.WriteUndoDataForBlock(blockundo, state, pindex, m_params)) {
2207
2169
  return false;
2208
2170
  }
@@ -2272,7 +2234,6 @@ bool CChainState::FlushStateToDisk(
2272
2234
  assert(this->CanFlushToDisk());
2273
2235
  static std::chrono::microseconds nLastWrite{0};
2274
2236
  static std::chrono::microseconds nLastFlush{0};
2275
- std::set<int> setFilesToPrune;
2276
2237
  bool full_flush_completed = false;
2277
2238
 
2278
2239
  const size_t coins_count = CoinsTip().GetCacheSize();
@@ -2280,12 +2241,10 @@ bool CChainState::FlushStateToDisk(
2280
2241
 
2281
2242
  try {
2282
2243
  {
2283
- bool fFlushForPrune = false;
2284
2244
  bool fDoFullFlush = false;
2285
2245
 
2286
2246
  CoinsCacheSizeState cache_state = GetCoinsCacheSizeState();
2287
2247
  LOCK(m_blockman.cs_LastBlockFile);
2288
- if (fPruneMode && (m_blockman.m_check_for_pruning || nManualPruneHeight > 0) && !fReindex) {
2289
2248
  // make sure we don't prune above the blockfilterindexes bestblocks
2290
2249
  // pruning is height-based
2291
2250
  int last_prune = m_chain.Height(); // last height we can prune
@@ -2293,24 +2252,6 @@ bool CChainState::FlushStateToDisk(
2293
2252
  last_prune = std::max(1, std::min(last_prune, index.GetSummary().best_block_height));
2294
2253
  });
2295
2254
 
2296
- if (nManualPruneHeight > 0) {
2297
- LOG_TIME_MILLIS_WITH_CATEGORY("find files to prune (manual)", BCLog::BENCH);
2298
-
2299
- m_blockman.FindFilesToPruneManual(setFilesToPrune, std::min(last_prune, nManualPruneHeight), m_chain.Height());
2300
- } else {
2301
- LOG_TIME_MILLIS_WITH_CATEGORY("find files to prune", BCLog::BENCH);
2302
-
2303
- m_blockman.FindFilesToPrune(setFilesToPrune, m_params.PruneAfterHeight(), m_chain.Height(), last_prune, IsInitialBlockDownload());
2304
- m_blockman.m_check_for_pruning = false;
2305
- }
2306
- if (!setFilesToPrune.empty()) {
2307
- fFlushForPrune = true;
2308
- if (!fHavePruned) {
2309
- m_blockman.m_block_tree_db->WriteFlag("prunedblockfiles", true);
2310
- fHavePruned = true;
2311
- }
2312
- }
2313
- }
2314
2255
  const auto nNow = GetTime<std::chrono::microseconds>();
2315
2256
  // Avoid writing/flushing immediately after startup.
2316
2257
  if (nLastWrite.count() == 0) {
@@ -2328,7 +2269,7 @@ bool CChainState::FlushStateToDisk(
2328
2269
  // It's been very long since we flushed the cache. Do this infrequently, to optimize cache usage.
2329
2270
  bool fPeriodicFlush = mode == FlushStateMode::PERIODIC && nNow > nLastFlush + DATABASE_FLUSH_INTERVAL;
2330
2271
  // Combine all conditions that result in a full cache flush.
2331
- fDoFullFlush = (mode == FlushStateMode::ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush || fFlushForPrune;
2272
+ fDoFullFlush = (mode == FlushStateMode::ALWAYS) || fCacheLarge || fCacheCritical || fPeriodicFlush;
2332
2273
  // Write blocks and block index to disk.
2333
2274
  if (fDoFullFlush || fPeriodicWrite) {
2334
2275
  // Ensure we can write block index
@@ -2350,12 +2291,6 @@ bool CChainState::FlushStateToDisk(
2350
2291
  return AbortNode(state, "Failed to write to block index database");
2351
2292
  }
2352
2293
  }
2353
- // Finally remove any pruned files
2354
- if (fFlushForPrune) {
2355
- LOG_TIME_MILLIS_WITH_CATEGORY("unlink pruned files", BCLog::BENCH);
2356
-
2357
- UnlinkPrunedFiles(setFilesToPrune);
2358
- }
2359
2294
  nLastWrite = nNow;
2360
2295
  }
2361
2296
  // Flush best chain related state. This can only be done if the blocks / block index write was also done.
@@ -2376,12 +2311,11 @@ bool CChainState::FlushStateToDisk(
2376
2311
  return AbortNode(state, "Failed to write to coin database");
2377
2312
  nLastFlush = nNow;
2378
2313
  full_flush_completed = true;
2379
- TRACE5(utxocache, flush,
2314
+ TRACE4(utxocache, flush,
2380
2315
  (int64_t)(GetTimeMicros() - nNow.count()), // in microseconds (µs)
2381
2316
  (u_int32_t)mode,
2382
2317
  (u_int64_t)coins_count,
2383
- (u_int64_t)coins_mem_usage,
2384
- (bool)fFlushForPrune);
2318
+ (u_int64_t)coins_mem_usage);
2385
2319
  }
2386
2320
  }
2387
2321
  if (full_flush_completed) {
@@ -2402,25 +2336,6 @@ void CChainState::ForceFlushStateToDisk()
2402
2336
  }
2403
2337
  }
2404
2338
 
2405
- void CChainState::PruneAndFlush()
2406
- {
2407
- BlockValidationState state;
2408
- m_blockman.m_check_for_pruning = true;
2409
- if (!this->FlushStateToDisk(state, FlushStateMode::NONE)) {
2410
- LogPrintf("%s: failed to flush state (%s)\n", __func__, state.ToString());
2411
- }
2412
- }
2413
-
2414
- static void DoWarning(const bilingual_str& warning)
2415
- {
2416
- static bool fWarned = false;
2417
- SetMiscWarning(warning);
2418
- if (!fWarned) {
2419
- AlertNotify(warning.original);
2420
- fWarned = true;
2421
- }
2422
- }
2423
-
2424
2339
  /** Private helper function that concatenates warning messages. */
2425
2340
  static void AppendWarning(bilingual_str& res, const bilingual_str& warn)
2426
2341
  {
@@ -2441,7 +2356,7 @@ static void UpdateTipLog(
2441
2356
  LogPrintf("%s%s: new best=%s height=%d version=0x%08x log2_work=%f tx=%lu date='%s' progress=%f cache=%.1fMiB(%utxo)%s\n",
2442
2357
  prefix, func_name,
2443
2358
  tip->GetBlockHash().ToString(), tip->nHeight, tip->nVersion,
2444
- log(tip->nChainWork.getdouble()) / log(2.0), (unsigned long)tip->nChainTx,
2359
+ log(tip->nChainTrust.getdouble()) / log(2.0), (unsigned long)tip->nChainTx,
2445
2360
  FormatISO8601DateTime(tip->GetBlockTime()),
2446
2361
  GuessVerificationProgress(params.TxData(), tip),
2447
2362
  coins_tip.DynamicMemoryUsage() * (1.0 / (1 << 20)),
@@ -2479,19 +2394,8 @@ void CChainState::UpdateTip(const CBlockIndex* pindexNew)
2479
2394
  bilingual_str warning_messages;
2480
2395
  if (!this->IsInitialBlockDownload()) {
2481
2396
  const CBlockIndex* pindex = pindexNew;
2482
- for (int bit = 0; bit < VERSIONBITS_NUM_BITS; bit++) {
2483
- WarningBitsConditionChecker checker(bit);
2484
- ThresholdState state = checker.GetStateFor(pindex, m_params.GetConsensus(), warningcache[bit]);
2485
- if (state == ThresholdState::ACTIVE || state == ThresholdState::LOCKED_IN) {
2486
- const bilingual_str warning = strprintf(_("Unknown new rules activated (versionbit %i)"), bit);
2487
- if (state == ThresholdState::ACTIVE) {
2488
- DoWarning(warning);
2489
- } else {
2490
- AppendWarning(warning_messages, warning);
2491
- }
2492
- }
2493
- }
2494
2397
  }
2398
+
2495
2399
  UpdateTipLog(coins_tip, pindexNew, m_params, __func__, "", warning_messages.original);
2496
2400
  }
2497
2401
 
@@ -2704,7 +2608,7 @@ CBlockIndex* CChainState::FindMostWorkChain()
2704
2608
  bool fMissingData = !(pindexTest->nStatus & BLOCK_HAVE_DATA);
2705
2609
  if (fFailedChain || fMissingData) {
2706
2610
  // Candidate chain is not usable (either invalid or missing data)
2707
- if (fFailedChain && (m_chainman.m_best_invalid == nullptr || pindexNew->nChainWork > m_chainman.m_best_invalid->nChainWork)) {
2611
+ if (fFailedChain && (m_chainman.m_best_invalid == nullptr || pindexNew->nChainTrust > m_chainman.m_best_invalid->nChainTrust)) {
2708
2612
  m_chainman.m_best_invalid = pindexNew;
2709
2613
  }
2710
2614
  CBlockIndex *pindexFailed = pindexNew;
@@ -2815,7 +2719,7 @@ bool CChainState::ActivateBestChainStep(BlockValidationState& state, CBlockIndex
2815
2719
  }
2816
2720
  } else {
2817
2721
  PruneBlockIndexCandidates();
2818
- if (!pindexOldTip || m_chain.Tip()->nChainWork > pindexOldTip->nChainWork) {
2722
+ if (!pindexOldTip || m_chain.Tip()->nChainTrust > pindexOldTip->nChainTrust) {
2819
2723
  // We're in a better position than we were. Return temporarily to release the lock.
2820
2724
  fContinue = false;
2821
2725
  break;
@@ -2981,15 +2885,15 @@ bool CChainState::PreciousBlock(BlockValidationState& state, CBlockIndex* pindex
2981
2885
  AssertLockNotHeld(::cs_main);
2982
2886
  {
2983
2887
  LOCK(cs_main);
2984
- if (pindex->nChainWork < m_chain.Tip()->nChainWork) {
2888
+ if (pindex->nChainTrust < m_chain.Tip()->nChainTrust) {
2985
2889
  // Nothing to do, this block is not at the tip.
2986
2890
  return true;
2987
2891
  }
2988
- if (m_chain.Tip()->nChainWork > nLastPreciousChainwork) {
2892
+ if (m_chain.Tip()->nChainTrust > nLastPreciousChainwork) {
2989
2893
  // The chain has been extended since the last call, reset the counter.
2990
2894
  nBlockReverseSequenceId = -1;
2991
2895
  }
2992
- nLastPreciousChainwork = m_chain.Tip()->nChainWork;
2896
+ nLastPreciousChainwork = m_chain.Tip()->nChainTrust;
2993
2897
  setBlockIndexCandidates.erase(pindex);
2994
2898
  pindex->nSequenceId = nBlockReverseSequenceId;
2995
2899
  if (nBlockReverseSequenceId > std::numeric_limits<int32_t>::min()) {
@@ -3046,7 +2950,7 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pind
3046
2950
  !CBlockIndexWorkComparator()(candidate, pindex->pprev) &&
3047
2951
  candidate->IsValid(BLOCK_VALID_TRANSACTIONS) &&
3048
2952
  candidate->HaveTxsDownloaded()) {
3049
- candidate_blocks_by_work.insert(std::make_pair(candidate->nChainWork, candidate));
2953
+ candidate_blocks_by_work.insert(std::make_pair(candidate->nChainTrust, candidate));
3050
2954
  }
3051
2955
  }
3052
2956
  }
@@ -3096,7 +3000,7 @@ bool CChainState::InvalidateBlock(BlockValidationState& state, CBlockIndex* pind
3096
3000
  }
3097
3001
 
3098
3002
  // Add any equal or more work headers to setBlockIndexCandidates
3099
- auto candidate_it = candidate_blocks_by_work.lower_bound(invalid_walk_tip->pprev->nChainWork);
3003
+ auto candidate_it = candidate_blocks_by_work.lower_bound(invalid_walk_tip->pprev->nChainTrust);
3100
3004
  while (candidate_it != candidate_blocks_by_work.end()) {
3101
3005
  if (!CBlockIndexWorkComparator()(candidate_it->second, invalid_walk_tip->pprev)) {
3102
3006
  setBlockIndexCandidates.insert(candidate_it->second);
@@ -3195,7 +3099,7 @@ void CChainState::ReceivedBlockTransactions(const CBlock& block, CBlockIndex* pi
3195
3099
  pindexNew->nDataPos = pos.nPos;
3196
3100
  pindexNew->nUndoPos = 0;
3197
3101
  pindexNew->nStatus |= BLOCK_HAVE_DATA;
3198
- if (DeploymentActiveAt(*pindexNew, m_params.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT)) {
3102
+ if (pindexNew->pprev && IsBTC16BIPsEnabled(pindexNew->pprev->nTime)) {
3199
3103
  pindexNew->nStatus |= BLOCK_OPT_WITNESS;
3200
3104
  }
3201
3105
  pindexNew->RaiseValidity(BLOCK_VALID_TRANSACTIONS);
@@ -3239,7 +3143,7 @@ static bool CheckBlockHeader(const CBlockHeader& block, BlockValidationState& st
3239
3143
  return true;
3240
3144
  }
3241
3145
 
3242
- bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW, bool fCheckMerkleRoot)
3146
+ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW, bool fCheckMerkleRoot, bool fCheckSignature)
3243
3147
  {
3244
3148
  // These are checks that are independent of context.
3245
3149
 
@@ -3248,7 +3152,7 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu
3248
3152
 
3249
3153
  // Check that the header is valid (particularly PoW). This is mostly
3250
3154
  // redundant with the call in AcceptBlockHeader.
3251
- if (!CheckBlockHeader(block, state, consensusParams, fCheckPOW))
3155
+ if (!CheckBlockHeader(block, state, consensusParams, fCheckPOW && !block.IsProofOfStake()))
3252
3156
  return false;
3253
3157
 
3254
3158
  // Signet only: check block solution
@@ -3287,6 +3191,32 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu
3287
3191
  if (block.vtx[i]->IsCoinBase())
3288
3192
  return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-multiple", "more than one coinbase");
3289
3193
 
3194
+ // peercoin: only the second transaction can be the optional coinstake
3195
+ for (unsigned int i = 2; i < block.vtx.size(); i++)
3196
+ if (block.vtx[i]->IsCoinStake())
3197
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cs-missing", "coinstake in wrong position");
3198
+
3199
+ // peercoin: first coinbase output should be empty if proof-of-stake block
3200
+ if (block.IsProofOfStake() && !block.vtx[0]->vout[0].IsEmpty())
3201
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-notempty", "coinbase output not empty in PoS block");
3202
+
3203
+ // Check coinbase timestamp
3204
+ if (block.GetBlockTime() > (block.vtx[0]->nTime ? (int64_t)block.vtx[0]->nTime : block.GetBlockTime()) + (IsProtocolV09(block.GetBlockTime()) ? MAX_FUTURE_BLOCK_TIME : MAX_FUTURE_BLOCK_TIME_PREV9))
3205
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-time", "coinbase timestamp is too early");
3206
+
3207
+ // Check coinstake timestamp
3208
+ if (block.IsProofOfStake() && !CheckCoinStakeTimestamp(block.GetBlockTime(), block.vtx[1]->nTime ? (int64_t)block.vtx[1]->nTime : block.GetBlockTime()))
3209
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cs-time", "coinstake timestamp violation");
3210
+
3211
+ // Check coinbase reward
3212
+ CAmount nCoinbaseCost = 0;
3213
+ if (block.IsProofOfWork())
3214
+ nCoinbaseCost = (GetMinFee(*block.vtx[0], block.nTime) < PERKB_TX_FEE)? 0 : (GetMinFee(*block.vtx[0], block.nTime) - PERKB_TX_FEE);
3215
+ if (block.vtx[0]->GetValueOut() > (block.IsProofOfWork()? (GetProofOfWorkReward(block.nBits, block.GetBlockTime()) - nCoinbaseCost) : 0))
3216
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-cb-amount",
3217
+ strprintf("CheckBlock() : coinbase reward exceeded %s > %s",
3218
+ FormatMoney(block.vtx[0]->GetValueOut()),
3219
+ FormatMoney(block.IsProofOfWork()? GetProofOfWorkReward(block.nBits, block.GetBlockTime()) : 0)));
3290
3220
  // Check transactions
3291
3221
  // Must check for duplicate inputs (see CVE-2018-17144)
3292
3222
  for (const auto& tx : block.vtx) {
@@ -3297,6 +3227,9 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu
3297
3227
  assert(tx_state.GetResult() == TxValidationResult::TX_CONSENSUS);
3298
3228
  return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, tx_state.GetRejectReason(),
3299
3229
  strprintf("Transaction check failed (tx hash %s) %s", tx->GetHash().ToString(), tx_state.GetDebugMessage()));
3230
+ // peercoin: check transaction timestamp
3231
+ if (block.GetBlockTime() < (int64_t)tx->nTime)
3232
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-tx-time", strprintf("%s : block timestamp earlier than transaction timestamp", __func__));
3300
3233
  }
3301
3234
  }
3302
3235
  unsigned int nSigOps = 0;
@@ -3310,6 +3243,12 @@ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensu
3310
3243
  if (fCheckPOW && fCheckMerkleRoot)
3311
3244
  block.fChecked = true;
3312
3245
 
3246
+ // peercoin: check block signature
3247
+ // Only check block signature if check merkle root, c.f. commit 3cd01fdf
3248
+ // rfc6: validate signatures of proof of stake blocks only after 0.8 fork
3249
+ if (fCheckMerkleRoot && fCheckSignature && (block.IsProofOfStake() || !IsBTC16BIPsEnabled(block.GetBlockTime())) && !CheckBlockSignature(block))
3250
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-blk-sign", strprintf("%s : bad block signature", __func__));
3251
+
3313
3252
  return true;
3314
3253
  }
3315
3254
 
@@ -3317,7 +3256,7 @@ void UpdateUncommittedBlockStructures(CBlock& block, const CBlockIndex* pindexPr
3317
3256
  {
3318
3257
  int commitpos = GetWitnessCommitmentIndex(block);
3319
3258
  static const std::vector<unsigned char> nonce(32, 0x00);
3320
- if (commitpos != NO_WITNESS_COMMITMENT && DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT) && !block.vtx[0]->HasWitness()) {
3259
+ if (commitpos != NO_WITNESS_COMMITMENT && IsBTC16BIPsEnabled(pindexPrev->nTime) && !block.vtx[0]->HasWitness()) {
3321
3260
  CMutableTransaction tx(*block.vtx[0]);
3322
3261
  tx.vin[0].scriptWitness.stack.resize(1);
3323
3262
  tx.vin[0].scriptWitness.stack[0] = nonce;
@@ -3367,10 +3306,10 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio
3367
3306
  assert(pindexPrev != nullptr);
3368
3307
  const int nHeight = pindexPrev->nHeight + 1;
3369
3308
 
3370
- // Check proof of work
3309
+ // Check proof of work or proof-of-stake
3371
3310
  const Consensus::Params& consensusParams = params.GetConsensus();
3372
- if (block.nBits != GetNextWorkRequired(pindexPrev, &block, consensusParams))
3373
- return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "bad-diffbits", "incorrect proof of work");
3311
+ if (block.nBits != GetNextTargetRequired(pindexPrev, block.nFlags & CBlockIndex::BLOCK_PROOF_OF_STAKE, consensusParams))
3312
+ return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "bad-diffbits", "incorrect proof of work/stake");
3374
3313
 
3375
3314
  // Check against checkpoints
3376
3315
  if (fCheckpointsEnabled) {
@@ -3385,20 +3324,19 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio
3385
3324
  }
3386
3325
 
3387
3326
  // Check timestamp against prev
3388
- if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast())
3327
+ if (block.GetBlockTime() <= pindexPrev->GetMedianTimePast() || block.GetBlockTime() + (IsProtocolV09(block.GetBlockTime()) ? MAX_FUTURE_BLOCK_TIME : MAX_FUTURE_BLOCK_TIME_PREV9) < pindexPrev->GetBlockTime())
3389
3328
  return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, "time-too-old", "block's timestamp is too early");
3390
3329
 
3391
3330
  // Check timestamp
3392
- if (block.GetBlockTime() > nAdjustedTime + MAX_FUTURE_BLOCK_TIME)
3331
+ if (block.GetBlockTime() > nAdjustedTime + (IsProtocolV09(block.GetBlockTime()) ? MAX_FUTURE_BLOCK_TIME : MAX_FUTURE_BLOCK_TIME_PREV9))
3393
3332
  return state.Invalid(BlockValidationResult::BLOCK_TIME_FUTURE, "time-too-new", "block timestamp too far in the future");
3394
3333
 
3395
- // Reject blocks with outdated version
3396
- if ((block.nVersion < 2 && DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_HEIGHTINCB)) ||
3397
- (block.nVersion < 3 && DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_DERSIG)) ||
3398
- (block.nVersion < 4 && DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CLTV))) {
3334
+ // Reject outdated version blocks when 95% (75% on testnet) of the network has upgraded:
3335
+ // check for version 2, 3 and 4 upgrades
3336
+ if ((block.nVersion < 2 && IsProtocolV06(pindexPrev)) ||
3337
+ (block.nVersion < 4 && IsProtocolV12(pindexPrev)))
3399
3338
  return state.Invalid(BlockValidationResult::BLOCK_INVALID_HEADER, strprintf("bad-version(0x%08x)", block.nVersion),
3400
3339
  strprintf("rejected nVersion=0x%08x block", block.nVersion));
3401
- }
3402
3340
 
3403
3341
  return true;
3404
3342
  }
@@ -3409,13 +3347,13 @@ static bool ContextualCheckBlockHeader(const CBlockHeader& block, BlockValidatio
3409
3347
  * in ConnectBlock().
3410
3348
  * Note that -reindex-chainstate skips the validation that happens here!
3411
3349
  */
3412
- static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, const CBlockIndex* pindexPrev)
3350
+ static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& state, const CBlockIndex* pindexPrev)
3413
3351
  {
3414
3352
  const int nHeight = pindexPrev == nullptr ? 0 : pindexPrev->nHeight + 1;
3415
3353
 
3416
3354
  // Enforce BIP113 (Median Time Past).
3417
3355
  int nLockTimeFlags = 0;
3418
- if (DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_CSV)) {
3356
+ if (pindexPrev && IsBTC16BIPsEnabled(pindexPrev->nTime)) {
3419
3357
  assert(pindexPrev != nullptr);
3420
3358
  nLockTimeFlags |= LOCKTIME_MEDIAN_TIME_PAST;
3421
3359
  }
@@ -3432,7 +3370,7 @@ static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& stat
3432
3370
  }
3433
3371
 
3434
3372
  // Enforce rule that the coinbase starts with serialized block height
3435
- if (DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_HEIGHTINCB))
3373
+ if (pindexPrev && IsProtocolV06(pindexPrev) && block.nVersion >= 2)
3436
3374
  {
3437
3375
  CScript expect = CScript() << nHeight;
3438
3376
  if (block.vtx[0]->vin[0].scriptSig.size() < expect.size() ||
@@ -3450,7 +3388,7 @@ static bool ContextualCheckBlock(const CBlock& block, BlockValidationState& stat
3450
3388
  // {0xaa, 0x21, 0xa9, 0xed}, and the following 32 bytes are SHA256^2(witness root, witness reserved value). In case there are
3451
3389
  // multiple, the last one is used.
3452
3390
  bool fHaveWitness = false;
3453
- if (DeploymentActiveAfter(pindexPrev, consensusParams, Consensus::DEPLOYMENT_SEGWIT)) {
3391
+ if (pindexPrev && IsBTC16BIPsEnabled(pindexPrev->nTime)) {
3454
3392
  int commitpos = GetWitnessCommitmentIndex(block);
3455
3393
  if (commitpos != NO_WITNESS_COMMITMENT) {
3456
3394
  bool malleated = false;
@@ -3510,7 +3448,7 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida
3510
3448
  return true;
3511
3449
  }
3512
3450
 
3513
- if (!CheckBlockHeader(block, state, chainparams.GetConsensus())) {
3451
+ if (!CheckBlockHeader(block, state, chainparams.GetConsensus(), !(block.nFlags & CBlockIndex::BLOCK_PROOF_OF_STAKE))) {
3514
3452
  LogPrint(BCLog::VALIDATION, "%s: Consensus::CheckBlockHeader: %s, %s\n", __func__, hash.ToString(), state.ToString());
3515
3453
  return false;
3516
3454
  }
@@ -3580,22 +3518,39 @@ bool ChainstateManager::AcceptBlockHeader(const CBlockHeader& block, BlockValida
3580
3518
  }
3581
3519
 
3582
3520
  // Exposed wrapper for AcceptBlockHeader
3583
- bool ChainstateManager::ProcessNewBlockHeaders(const std::vector<CBlockHeader>& headers, BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex)
3521
+ bool ChainstateManager::ProcessNewBlockHeaders(int32_t& nPoSTemperature, const uint256& lastAcceptedHeader, const std::vector<CBlockHeader>& headers, BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex)
3584
3522
  {
3585
3523
  AssertLockNotHeld(cs_main);
3586
3524
  {
3587
3525
  LOCK(cs_main);
3526
+
3527
+ int nCooling = POW_HEADER_COOLING;
3528
+ if (headers[0].hashPrevBlock != lastAcceptedHeader && !lastAcceptedHeader.IsNull()) {
3529
+ nPoSTemperature += (18 + headers.size()) / 10;
3530
+ nCooling = 0;
3531
+ }
3532
+
3588
3533
  for (const CBlockHeader& header : headers) {
3534
+ bool fPoS = header.nFlags & CBlockIndex::BLOCK_PROOF_OF_STAKE;
3535
+
3589
3536
  CBlockIndex *pindex = nullptr; // Use a temp pindex instead of ppindex to avoid a const_cast
3590
3537
  bool accepted{AcceptBlockHeader(header, state, chainparams, &pindex)};
3591
3538
  ActiveChainstate().CheckBlockIndex();
3592
3539
 
3593
3540
  if (!accepted) {
3541
+ nPoSTemperature += POW_HEADER_COOLING;
3594
3542
  return false;
3595
3543
  }
3596
3544
  if (ppindex) {
3597
3545
  *ppindex = pindex;
3598
3546
  }
3547
+
3548
+ if (fPoS) {
3549
+ nPoSTemperature++;
3550
+ } else { // PoW
3551
+ nPoSTemperature -= nCooling;
3552
+ nPoSTemperature = std::max((int)nPoSTemperature, 0);
3553
+ }
3599
3554
  }
3600
3555
  }
3601
3556
  if (NotifyHeaderTip(ActiveChainstate())) {
@@ -3613,6 +3568,7 @@ bool ChainstateManager::ProcessNewBlockHeaders(const std::vector<CBlockHeader>&
3613
3568
  bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, BlockValidationState& state, CBlockIndex** ppindex, bool fRequested, const FlatFilePos* dbp, bool* fNewBlock)
3614
3569
  {
3615
3570
  const CBlock& block = *pblock;
3571
+ bool fCheckPoS = true;
3616
3572
 
3617
3573
  if (fNewBlock) *fNewBlock = false;
3618
3574
  AssertLockHeld(cs_main);
@@ -3626,11 +3582,17 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block
3626
3582
  if (!accepted_header)
3627
3583
  return false;
3628
3584
 
3585
+ // peercoin: we should only accept blocks that can be connected to a prev block with validated PoS
3586
+ if (fCheckPoS && pindex->pprev && !pindex->pprev->IsValid(BLOCK_VALID_TRANSACTIONS)) {
3587
+ return error("%s: this block does not connect to any valid known block", __func__);
3588
+ }
3589
+
3629
3590
  // Try to process all requested blocks that we don't have, but only
3630
3591
  // process an unrequested block if it's new and has enough work to
3631
3592
  // advance our tip, and isn't too many blocks ahead.
3632
3593
  bool fAlreadyHave = pindex->nStatus & BLOCK_HAVE_DATA;
3633
- bool fHasMoreOrSameWork = (m_chain.Tip() ? pindex->nChainWork >= m_chain.Tip()->nChainWork : true);
3594
+ bool fHasMoreOrSameWork = (m_chain.Tip() ? pindex->nChainTrust >= m_chain.Tip()->nChainTrust : true);
3595
+
3634
3596
  // Blocks that are too out-of-order needlessly limit the effectiveness of
3635
3597
  // pruning, because pruning will not delete block files that contain any
3636
3598
  // blocks which are too close in height to the tip. Apply this test
@@ -3656,11 +3618,11 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block
3656
3618
  // If our tip is behind, a peer could try to send us
3657
3619
  // low-work blocks on a fake chain that we would never
3658
3620
  // request; don't process these.
3659
- if (pindex->nChainWork < nMinimumChainWork) return true;
3621
+ if (pindex->nChainTrust < nMinimumChainWork) return true;
3660
3622
  }
3661
3623
 
3662
3624
  if (!CheckBlock(block, state, m_params.GetConsensus()) ||
3663
- !ContextualCheckBlock(block, state, m_params.GetConsensus(), pindex->pprev)) {
3625
+ !ContextualCheckBlock(block, state, pindex->pprev)) {
3664
3626
  if (state.IsInvalid() && state.GetResult() != BlockValidationResult::BLOCK_MUTATED) {
3665
3627
  pindex->nStatus |= BLOCK_FAILED_VALID;
3666
3628
  m_blockman.m_dirty_blockindex.insert(pindex);
@@ -3668,9 +3630,16 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block
3668
3630
  return error("%s: %s", __func__, state.ToString());
3669
3631
  }
3670
3632
 
3633
+ // peercoin: check PoS
3634
+ if (fCheckPoS && !PeercoinContextualBlockChecks(block, state, pindex, false, m_chainman.ActiveChainstate())) {
3635
+ pindex->nStatus |= BLOCK_FAILED_VALID;
3636
+ m_blockman.m_dirty_blockindex.insert(pindex);
3637
+ return state.Invalid(BlockValidationResult::BLOCK_CONSENSUS, "bad-pos", "proof of stake is incorrect");
3638
+ }
3639
+
3671
3640
  // Header is valid/has work, merkle tree and segwit merkle tree are good...RELAY NOW
3672
3641
  // (but if it does not build on our best tip, let the SendMessages loop relay it)
3673
- if (!IsInitialBlockDownload() && m_chain.Tip() == pindex->pprev)
3642
+ if (!m_chainman.ActiveChainstate().IsInitialBlockDownload() && m_chain.Tip() == pindex->pprev)
3674
3643
  GetMainSignals().NewPoWValidBlock(pindex, pblock);
3675
3644
 
3676
3645
  // Write block to history file
@@ -3687,19 +3656,19 @@ bool CChainState::AcceptBlock(const std::shared_ptr<const CBlock>& pblock, Block
3687
3656
  }
3688
3657
 
3689
3658
  FlushStateToDisk(state, FlushStateMode::NONE);
3690
-
3691
3659
  CheckBlockIndex();
3692
3660
 
3693
3661
  return true;
3694
3662
  }
3695
3663
 
3696
- bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block)
3664
+ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block, CBlockIndex** ppindex, bool* fPoSDuplicate)
3697
3665
  {
3698
3666
  AssertLockNotHeld(cs_main);
3699
3667
 
3700
3668
  {
3701
3669
  CBlockIndex *pindex = nullptr;
3702
3670
  if (new_block) *new_block = false;
3671
+ if (fPoSDuplicate) *fPoSDuplicate = false;
3703
3672
  BlockValidationState state;
3704
3673
 
3705
3674
  // CheckBlock() does not support multi-threaded block validation because CBlock::fChecked can cause data race.
@@ -3716,10 +3685,19 @@ bool ChainstateManager::ProcessNewBlock(const CChainParams& chainparams, const s
3716
3685
  // Store to disk
3717
3686
  ret = ActiveChainstate().AcceptBlock(block, state, &pindex, force_processing, nullptr, new_block);
3718
3687
  }
3688
+ if (ppindex)
3689
+ *ppindex = ret ? pindex : nullptr;
3719
3690
  if (!ret) {
3720
3691
  GetMainSignals().BlockChecked(*block, state);
3721
3692
  return error("%s: AcceptBlock FAILED (%s)", __func__, state.ToString());
3722
3693
  }
3694
+
3695
+ if (pindex->IsProofOfStake() && !ActiveChainstate().IsInitialBlockDownload()) {
3696
+ int32_t ndx = univHash(pindex->hashProofOfStake);
3697
+ if (fPoSDuplicate && vStakeSeen[ndx] == pindex->hashProofOfStake)
3698
+ *fPoSDuplicate = true;
3699
+ vStakeSeen[ndx] = pindex->hashProofOfStake;
3700
+ }
3723
3701
  }
3724
3702
 
3725
3703
  NotifyHeaderTip(ActiveChainstate());
@@ -3768,7 +3746,7 @@ bool TestBlockValidity(BlockValidationState& state,
3768
3746
  return error("%s: Consensus::ContextualCheckBlockHeader: %s", __func__, state.ToString());
3769
3747
  if (!CheckBlock(block, state, chainparams.GetConsensus(), fCheckPOW, fCheckMerkleRoot))
3770
3748
  return error("%s: Consensus::CheckBlock: %s", __func__, state.ToString());
3771
- if (!ContextualCheckBlock(block, state, chainparams.GetConsensus(), pindexPrev))
3749
+ if (!ContextualCheckBlock(block, state, pindexPrev))
3772
3750
  return error("%s: Consensus::ContextualCheckBlock: %s", __func__, state.ToString());
3773
3751
  if (!chainstate.ConnectBlock(block, state, &indexDummy, viewNew, true)) {
3774
3752
  return false;
@@ -3778,16 +3756,6 @@ bool TestBlockValidity(BlockValidationState& state,
3778
3756
  return true;
3779
3757
  }
3780
3758
 
3781
- /* This function is called from the RPC code for pruneblockchain */
3782
- void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight)
3783
- {
3784
- BlockValidationState state;
3785
- if (!active_chainstate.FlushStateToDisk(
3786
- state, FlushStateMode::NONE, nManualPruneHeight)) {
3787
- LogPrintf("%s: failed to flush state (%s)\n", __func__, state.ToString());
3788
- }
3789
- }
3790
-
3791
3759
  void CChainState::LoadMempool(const ArgsManager& args)
3792
3760
  {
3793
3761
  if (!m_mempool) return;
@@ -3874,10 +3842,10 @@ bool CVerifyDB::VerifyDB(
3874
3842
  if (pindex->nHeight <= chainstate.m_chain.Height() - nCheckDepth) {
3875
3843
  break;
3876
3844
  }
3877
- if ((fPruneMode || is_snapshot_cs) && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
3878
- // If pruning or running under an assumeutxo snapshot, only go
3845
+ if (is_snapshot_cs && !(pindex->nStatus & BLOCK_HAVE_DATA)) {
3846
+ // If running under an assumeutxo snapshot, only go
3879
3847
  // back as far as we have data.
3880
- LogPrintf("VerifyDB(): block verification stopping at height %d (pruning, no data)\n", pindex->nHeight);
3848
+ LogPrintf("VerifyDB(): block verification stopping at height %d (no data)\n", pindex->nHeight);
3881
3849
  break;
3882
3850
  }
3883
3851
  CBlock block;
@@ -3968,7 +3936,7 @@ bool CChainState::RollforwardBlock(const CBlockIndex* pindex, CCoinsViewCache& i
3968
3936
  }
3969
3937
  }
3970
3938
  // Pass check = true as every addition may be an overwrite.
3971
- AddCoins(inputs, *tx, pindex->nHeight, true);
3939
+ AddCoins(inputs, *tx, pindex->nHeight, true, IsProtocolV12(pindex));
3972
3940
  }
3973
3941
  return true;
3974
3942
  }
@@ -4047,7 +4015,7 @@ bool CChainState::NeedsRedownload() const
4047
4015
  // At and above m_params.SegwitHeight, segwit consensus rules must be validated
4048
4016
  CBlockIndex* block{m_chain.Tip()};
4049
4017
 
4050
- while (block != nullptr && DeploymentActiveAt(*block, m_params.GetConsensus(), Consensus::DEPLOYMENT_SEGWIT)) {
4018
+ while (block != nullptr && block->pprev && IsBTC16BIPsEnabled(block->pprev->nTime)) {
4051
4019
  if (!(block->nStatus & BLOCK_OPT_WITNESS)) {
4052
4020
  // block is insufficiently validated for a segwit client
4053
4021
  return true;
@@ -4074,11 +4042,6 @@ void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman)
4074
4042
  chainman.Unload();
4075
4043
  pindexBestHeader = nullptr;
4076
4044
  if (mempool) mempool->clear();
4077
- g_versionbitscache.Clear();
4078
- for (int b = 0; b < VERSIONBITS_NUM_BITS; b++) {
4079
- warningcache[b].clear();
4080
- }
4081
- fHavePruned = false;
4082
4045
  }
4083
4046
 
4084
4047
  bool ChainstateManager::LoadBlockIndex()
@@ -4330,16 +4293,8 @@ void CChainState::CheckBlockIndex()
4330
4293
  if (!pindex->HaveTxsDownloaded()) assert(pindex->nSequenceId <= 0); // nSequenceId can't be set positive for blocks that aren't linked (negative is used for preciousblock)
4331
4294
  // VALID_TRANSACTIONS is equivalent to nTx > 0 for all nodes (whether or not pruning has occurred).
4332
4295
  // HAVE_DATA is only equivalent to nTx > 0 (or VALID_TRANSACTIONS) if no pruning has occurred.
4333
- // Unless these indexes are assumed valid and pending block download on a
4334
- // background chainstate.
4335
- if (!fHavePruned && !pindex->IsAssumedValid()) {
4336
- // If we've never pruned, then HAVE_DATA should be equivalent to nTx > 0
4337
- assert(!(pindex->nStatus & BLOCK_HAVE_DATA) == (pindex->nTx == 0));
4338
- assert(pindexFirstMissing == pindexFirstNeverProcessed);
4339
- } else {
4340
- // If we have pruned, then we can only say that HAVE_DATA implies nTx > 0
4341
- if (pindex->nStatus & BLOCK_HAVE_DATA) assert(pindex->nTx > 0);
4342
- }
4296
+ assert(!(pindex->nStatus & BLOCK_HAVE_DATA) == (pindex->nTx == 0));
4297
+ assert(pindexFirstMissing == pindexFirstNeverProcessed);
4343
4298
  if (pindex->nStatus & BLOCK_HAVE_UNDO) assert(pindex->nStatus & BLOCK_HAVE_DATA);
4344
4299
  if (pindex->IsAssumedValid()) {
4345
4300
  // Assumed-valid blocks should have some nTx value.
@@ -4355,7 +4310,7 @@ void CChainState::CheckBlockIndex()
4355
4310
  assert((pindexFirstNeverProcessed == nullptr) == pindex->HaveTxsDownloaded());
4356
4311
  assert((pindexFirstNotTransactionsValid == nullptr) == pindex->HaveTxsDownloaded());
4357
4312
  assert(pindex->nHeight == nHeight); // nHeight must be consistent.
4358
- assert(pindex->pprev == nullptr || pindex->nChainWork >= pindex->pprev->nChainWork); // For every block except the genesis block, the chainwork must be larger than the parent's.
4313
+ assert(pindex->pprev == nullptr || pindex->nChainTrust >= pindex->pprev->nChainTrust); // For every block except the genesis block, the chainwork must be larger than the parent's.
4359
4314
  assert(nHeight < 2 || (pindex->pskip && (pindex->pskip->nHeight < nHeight))); // The pskip pointer must point back for all but the first 2 blocks.
4360
4315
  assert(pindexFirstNotTreeValid == nullptr); // All m_blockman.m_block_index entries must at least be TREE valid
4361
4316
  if ((pindex->nStatus & BLOCK_VALID_MASK) >= BLOCK_VALID_TREE) assert(pindexFirstNotTreeValid == nullptr); // TREE valid implies all parents are TREE valid
@@ -4371,8 +4326,7 @@ void CChainState::CheckBlockIndex()
4371
4326
 
4372
4327
  // If this block sorts at least as good as the current tip and
4373
4328
  // is valid and we have all data for its parents, it must be in
4374
- // setBlockIndexCandidates. m_chain.Tip() must also be there
4375
- // even if some data has been pruned.
4329
+ // setBlockIndexCandidates. m_chain.Tip() must also be there.
4376
4330
  //
4377
4331
  // Don't perform this check for the background chainstate since
4378
4332
  // its setBlockIndexCandidates shouldn't have some entries (i.e. those past the
@@ -4404,23 +4358,6 @@ void CChainState::CheckBlockIndex()
4404
4358
  }
4405
4359
  if (!(pindex->nStatus & BLOCK_HAVE_DATA)) assert(!foundInUnlinked); // Can't be in m_blocks_unlinked if we don't HAVE_DATA
4406
4360
  if (pindexFirstMissing == nullptr) assert(!foundInUnlinked); // We aren't missing data for any parent -- cannot be in m_blocks_unlinked.
4407
- if (pindex->pprev && (pindex->nStatus & BLOCK_HAVE_DATA) && pindexFirstNeverProcessed == nullptr && pindexFirstMissing != nullptr) {
4408
- // We HAVE_DATA for this block, have received data for all parents at some point, but we're currently missing data for some parent.
4409
- assert(fHavePruned); // We must have pruned.
4410
- // This block may have entered m_blocks_unlinked if:
4411
- // - it has a descendant that at some point had more work than the
4412
- // tip, and
4413
- // - we tried switching to that descendant but were missing
4414
- // data for some intermediate block between m_chain and the
4415
- // tip.
4416
- // So if this block is itself better than m_chain.Tip() and it wasn't in
4417
- // setBlockIndexCandidates, then it must be in m_blocks_unlinked.
4418
- if (!CBlockIndexWorkComparator()(pindex, m_chain.Tip()) && setBlockIndexCandidates.count(pindex) == 0) {
4419
- if (pindexFirstInvalid == nullptr) {
4420
- assert(foundInUnlinked);
4421
- }
4422
- }
4423
- }
4424
4361
  // assert(pindex->GetBlockHash() == pindex->GetBlockHeader().GetHash()); // Perhaps too slow
4425
4362
  // End: actual consistency checks.
4426
4363
 
@@ -4678,6 +4615,126 @@ double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex *pin
4678
4615
  return std::min<double>(pindex->nChainTx / fTxTotal, 1.0);
4679
4616
  }
4680
4617
 
4618
+
4619
+
4620
+
4621
+
4622
+ // peercoin: total coin age spent in transaction, in the unit of coin-days.
4623
+ // Only those coins meeting minimum age requirement counts. As those
4624
+ // transactions not in main chain are not currently indexed so we
4625
+ // might not find out about their coin age. Older transactions are
4626
+ // guaranteed to be in main chain by sync-checkpoint. This rule is
4627
+ // introduced to help nodes establish a consistent view of the coin
4628
+ // age (trust score) of competing branches.
4629
+ bool GetCoinAge(const CTransaction& tx, const CCoinsViewCache &view, uint64_t& nCoinAge, unsigned int nTimeTx, bool isTrueCoinAge)
4630
+ {
4631
+ arith_uint256 bnCentSecond = 0; // coin age in the unit of cent-seconds
4632
+ nCoinAge = 0;
4633
+
4634
+ if (tx.IsCoinBase())
4635
+ return true;
4636
+
4637
+ // Transaction index is required to get to block header
4638
+ if (!g_txindex)
4639
+ return false; // Transaction index not available
4640
+
4641
+ for (const auto& txin : tx.vin)
4642
+ {
4643
+ // First try finding the previous transaction in database
4644
+ const COutPoint &prevout = txin.prevout;
4645
+ Coin coin;
4646
+
4647
+ if (isTrueCoinAge && !view.GetCoin(prevout, coin))
4648
+ continue; // previous transaction not in main chain
4649
+ if (nTimeTx < coin.nTime)
4650
+ return false; // Transaction timestamp violation
4651
+
4652
+ CDiskTxPos postx;
4653
+ CBlockHeader header;
4654
+ CTransactionRef txPrev;
4655
+ auto it = g_txindex->cachedTxs.find(prevout.hash);
4656
+ if (it != g_txindex->cachedTxs.end()) {
4657
+ header = it->second.first;
4658
+ txPrev = it->second.second;
4659
+ } else {
4660
+ if (g_txindex->FindTxPosition(prevout.hash, postx)) {
4661
+ CAutoFile file(OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
4662
+ try {
4663
+ file >> header;
4664
+ fseek(file.Get(), postx.nTxOffset, SEEK_CUR);
4665
+ file >> txPrev;
4666
+ } catch (std::exception &e) {
4667
+ return error("%s() : deserialize or I/O error in GetCoinAge()", __PRETTY_FUNCTION__);
4668
+ }
4669
+ } else
4670
+ return error("%s() : tx missing in tx index in GetCoinAge()", __PRETTY_FUNCTION__);
4671
+ g_txindex->cachedTxs[prevout.hash] = std::pair(header,txPrev);
4672
+ }
4673
+
4674
+ if (txPrev->GetHash() != prevout.hash)
4675
+ return error("%s() : txid mismatch in GetCoinAge()", __PRETTY_FUNCTION__);
4676
+
4677
+ if (header.GetBlockTime() + Params().GetConsensus().nStakeMinAge > nTimeTx)
4678
+ continue; // only count coins meeting min age requirement
4679
+
4680
+ int64_t nValueIn = txPrev->vout[txin.prevout.n].nValue;
4681
+ int nEffectiveAge = nTimeTx-(txPrev->nTime ? txPrev->nTime : header.GetBlockTime());
4682
+
4683
+ if (!isTrueCoinAge || IsProtocolV09(nTimeTx))
4684
+ nEffectiveAge = std::min(nEffectiveAge, 365 * 24 * 60 * 60);
4685
+
4686
+ bnCentSecond += arith_uint256(nValueIn) * nEffectiveAge / CENT;
4687
+
4688
+ if (gArgs.GetBoolArg("-printcoinage", false))
4689
+ LogPrintf("coin age nValueIn=%-12lld nTimeDiff=%d bnCentSecond=%s\n", nValueIn, nEffectiveAge, bnCentSecond.ToString());
4690
+ }
4691
+
4692
+ arith_uint256 bnCoinDay = bnCentSecond * CENT / COIN / (24 * 60 * 60);
4693
+ if (gArgs.GetBoolArg("-printcoinage", false))
4694
+ LogPrintf("coin age bnCoinDay=%s\n", bnCoinDay.ToString());
4695
+ nCoinAge = bnCoinDay.GetLow64();
4696
+ return true;
4697
+ }
4698
+
4699
+ // peercoin: sign block
4700
+ typedef std::vector<unsigned char> valtype;
4701
+ bool SignBlock(CBlock& block, const CWallet& keystore)
4702
+ {
4703
+ std::vector<valtype> vSolutions;
4704
+ const CTxOut& txout = block.IsProofOfStake()? block.vtx[1]->vout[1] : block.vtx[0]->vout[0];
4705
+
4706
+ if (Solver(txout.scriptPubKey, vSolutions) != TxoutType::PUBKEY)
4707
+ return false;
4708
+
4709
+ // Sign
4710
+ const valtype& vchPubKey = vSolutions[0];
4711
+ CKey key;
4712
+ if (!keystore.GetLegacyScriptPubKeyMan()->GetKey(CKeyID(Hash160(vchPubKey)), key))
4713
+ return false;
4714
+ if (key.GetPubKey() != CPubKey(vchPubKey))
4715
+ return false;
4716
+ return key.Sign(block.GetHash(), block.vchBlockSig, 0);
4717
+ }
4718
+
4719
+ // peercoin: check block signature
4720
+ bool CheckBlockSignature(const CBlock& block)
4721
+ {
4722
+ if (block.GetHash() == Params().GetConsensus().hashGenesisBlock)
4723
+ return block.vchBlockSig.empty();
4724
+
4725
+ std::vector<valtype> vSolutions;
4726
+ const CTxOut& txout = block.IsProofOfStake()? block.vtx[1]->vout[1] : block.vtx[0]->vout[0];
4727
+
4728
+ if (Solver(txout.scriptPubKey, vSolutions) != TxoutType::PUBKEY)
4729
+ return false;
4730
+
4731
+ const valtype& vchPubKey = vSolutions[0];
4732
+ CPubKey key(vchPubKey);
4733
+ if (block.vchBlockSig.empty())
4734
+ return false;
4735
+ return key.Verify(block.GetHash(), block.vchBlockSig);
4736
+ }
4737
+
4681
4738
  std::optional<uint256> ChainstateManager::SnapshotBlockhash() const
4682
4739
  {
4683
4740
  LOCK(::cs_main);
@@ -5009,7 +5066,7 @@ bool ChainstateManager::PopulateAndValidateSnapshot(
5009
5066
 
5010
5067
  // Fake BLOCK_OPT_WITNESS so that CChainState::NeedsRedownload()
5011
5068
  // won't ask to rewind the entire assumed-valid chain on startup.
5012
- if (DeploymentActiveAt(*index, ::Params().GetConsensus(), Consensus::DEPLOYMENT_SEGWIT)) {
5069
+ if (IsBTC16BIPsEnabled(index->nTime)) {
5013
5070
  index->nStatus |= BLOCK_OPT_WITNESS;
5014
5071
  }
5015
5072
 
src/validation.h CHANGED
@@ -16,16 +16,17 @@
16
16
  #include <consensus/amount.h>
17
17
  #include <fs.h>
18
18
  #include <node/blockstorage.h>
19
- #include <policy/feerate.h>
20
19
  #include <policy/packages.h>
21
20
  #include <script/script_error.h>
22
21
  #include <sync.h>
22
+ #include <chain.h>
23
23
  #include <txdb.h>
24
24
  #include <txmempool.h> // For CTxMemPool::cs
25
25
  #include <uint256.h>
26
26
  #include <util/check.h>
27
27
  #include <util/hasher.h>
28
28
  #include <util/translation.h>
29
+ #include <wallet/wallet.h>
29
30
 
30
31
  #include <atomic>
31
32
  #include <map>
@@ -41,8 +42,14 @@
41
42
  class CChainState;
42
43
  class CBlockTreeDB;
43
44
  class CChainParams;
45
+ namespace wallet {
46
+ class CWallet;
47
+ } // namespace wallet
48
+ //class CWallet;
49
+ using wallet::CWallet;
44
50
  class CTxMemPool;
45
51
  class ChainstateManager;
52
+ class CKeyStore;
46
53
  struct ChainTxData;
47
54
  struct DisconnectedBlockTransactions;
48
55
  struct PrecomputedTransactionData;
@@ -52,8 +59,6 @@ namespace node {
52
59
  class SnapshotMetadata;
53
60
  } // namespace node
54
61
 
55
- /** Default for -minrelaytxfee, minimum relay fee for transactions */
56
- static const unsigned int DEFAULT_MIN_RELAY_TX_FEE = 1000;
57
62
  /** Default for -limitancestorcount, max number of in-mempool ancestors */
58
63
  static const unsigned int DEFAULT_ANCESTOR_LIMIT = 25;
59
64
  /** Default for -limitancestorsize, maximum kilobytes of tx + all in-mempool ancestors */
@@ -80,7 +85,7 @@ static const int MAX_SCRIPTCHECK_THREADS = 15;
80
85
  static const int DEFAULT_SCRIPTCHECK_THREADS = 0;
81
86
  static const int64_t DEFAULT_MAX_TIP_AGE = 24 * 60 * 60;
82
87
  static const bool DEFAULT_CHECKPOINTS_ENABLED = true;
83
- static const bool DEFAULT_TXINDEX = false;
88
+ static const bool DEFAULT_TXINDEX = true; // peercoin: txindex is required for PoS calculations (might change in the future)
84
89
  static constexpr bool DEFAULT_COINSTATSINDEX{false};
85
90
  static const char* const DEFAULT_BLOCKFILTERINDEX = "0";
86
91
  /** Default for -persistmempool */
@@ -120,8 +125,7 @@ extern bool g_parallel_script_checks;
120
125
  extern bool fRequireStandard;
121
126
  extern bool fCheckBlockIndex;
122
127
  extern bool fCheckpointsEnabled;
123
- /** A fee rate smaller than this is considered zero fee (for relaying, mining and transaction creation) */
124
- extern CFeeRate minRelayTxFee;
128
+ extern bool fAlerts;
125
129
  /** If the tip is older than this (in seconds), the node is considered to be in initial block download. */
126
130
  extern int64_t nMaxTipAge;
127
131
 
@@ -134,9 +138,11 @@ extern arith_uint256 nMinimumChainWork;
134
138
  /** Best header we've seen so far (used for getheaders queries' starting points). */
135
139
  extern CBlockIndex *pindexBestHeader;
136
140
 
141
+
137
142
  /** Documentation for argument 'checklevel'. */
138
143
  extern const std::vector<std::string> CHECKLEVEL_DOC;
139
144
 
145
+
140
146
  /** Unload database information */
141
147
  void UnloadBlockIndex(CTxMemPool* mempool, ChainstateManager& chainman);
142
148
  /** Run instances of script checking worker threads */
@@ -144,15 +150,12 @@ void StartScriptCheckWorkerThreads(int threads_num);
144
150
  /** Stop all of the script checking worker threads */
145
151
  void StopScriptCheckWorkerThreads();
146
152
 
147
- CAmount GetBlockSubsidy(int nHeight, const Consensus::Params& consensusParams);
148
153
 
149
154
  bool AbortNode(BlockValidationState& state, const std::string& strMessage, const bilingual_str& userMessage = bilingual_str{});
150
155
 
151
156
  /** Guess verification progress (as a fraction between 0.0=genesis and 1.0=current tip). */
152
157
  double GuessVerificationProgress(const ChainTxData& data, const CBlockIndex* pindex);
153
158
 
154
- /** Prune block files up to a given height */
155
- void PruneBlockFilesManual(CChainState& active_chainstate, int nManualPruneHeight);
156
159
 
157
160
  /**
158
161
  * Validation result for a single transaction mempool acceptance.
@@ -272,7 +275,6 @@ MempoolAcceptResult AcceptToMemoryPool(CChainState& active_chainstate, const CTr
272
275
  PackageMempoolAcceptResult ProcessNewPackage(CChainState& active_chainstate, CTxMemPool& pool,
273
276
  const Package& txns, bool test_accept)
274
277
  EXCLUSIVE_LOCKS_REQUIRED(cs_main);
275
-
276
278
  /** Transaction validation functions */
277
279
 
278
280
  /**
@@ -351,7 +353,7 @@ void InitScriptExecutionCache();
351
353
  /** Functions for validating blocks and updating the block tree */
352
354
 
353
355
  /** Context-independent validity checks */
354
- bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true);
356
+ bool CheckBlock(const CBlock& block, BlockValidationState& state, const Consensus::Params& consensusParams, bool fCheckPOW = true, bool fCheckMerkleRoot = true, bool fCheckSignature = true);
355
357
 
356
358
  /** Check a block is completely valid from start to finish (only works on top of our current best block) */
357
359
  bool TestBlockValidity(BlockValidationState& state,
@@ -624,10 +626,6 @@ public:
624
626
  //! Unconditionally flush all changes to disk.
625
627
  void ForceFlushStateToDisk();
626
628
 
627
- //! Prune blockfiles from the disk if necessary and then flush chainstate changes
628
- //! if we pruned.
629
- void PruneAndFlush();
630
-
631
629
  /**
632
630
  * Find the best known block, and make it the tip of the block chain. The
633
631
  * result is either failure or an activated best chain. pblock is either
@@ -961,7 +959,7 @@ public:
961
959
  * @param[out] new_block A boolean which is set to indicate if the block was first received via this call
962
960
  * @returns If the block was processed, independently of block validity
963
961
  */
964
- bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block) LOCKS_EXCLUDED(cs_main);
962
+ bool ProcessNewBlock(const CChainParams& chainparams, const std::shared_ptr<const CBlock>& block, bool force_processing, bool* new_block, CBlockIndex** ppindex = nullptr, bool* fPoSDuplicate = nullptr) LOCKS_EXCLUDED(cs_main);
965
963
 
966
964
  /**
967
965
  * Process incoming block headers.
@@ -974,7 +972,7 @@ public:
974
972
  * @param[in] chainparams The params for the chain we want to connect to
975
973
  * @param[out] ppindex If set, the pointer will be set to point to the last new block index object for the given headers
976
974
  */
977
- bool ProcessNewBlockHeaders(const std::vector<CBlockHeader>& block, BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex = nullptr) LOCKS_EXCLUDED(cs_main);
975
+ bool ProcessNewBlockHeaders(int32_t& nPoSTemperature, const uint256& lastAcceptedHeader, const std::vector<CBlockHeader>& block, BlockValidationState& state, const CChainParams& chainparams, const CBlockIndex** ppindex = nullptr) LOCKS_EXCLUDED(cs_main);
978
976
 
979
977
  /**
980
978
  * Try to add a transaction to the memory pool.
@@ -1013,6 +1011,12 @@ bool DumpMempool(const CTxMemPool& pool, FopenFn mockable_fopen_function = fsbri
1013
1011
  /** Load the mempool from disk. */
1014
1012
  bool LoadMempool(CTxMemPool& pool, CChainState& active_chainstate, FopenFn mockable_fopen_function = fsbridge::fopen);
1015
1013
 
1014
+ // peercoin:
1015
+ CAmount GetProofOfWorkReward(unsigned int nBits, uint32_t nTime);
1016
+ CAmount GetProofOfStakeReward(int64_t nCoinAge, uint32_t nTime, uint64_t nMoneySupply);
1017
+ bool GetCoinAge(const CTransaction& tx, const CCoinsViewCache &view, uint64_t& nCoinAge, unsigned int nTimeTx, bool isTrueCoinAge = true); // peercoin: get transaction coin age
1018
+ bool SignBlock(CBlock& block, const CWallet& keystore);
1019
+ bool CheckBlockSignature(const CBlock& block);
1016
1020
  /**
1017
1021
  * Return the expected assumeutxo value for a given height, if one exists.
1018
1022
  *
src/validationinterface.h CHANGED
@@ -109,7 +109,6 @@ protected:
109
109
  * - SIZELIMIT (removed in size limiting if the mempool exceeds -maxmempool megabytes)
110
110
  * - REORG (removed during a reorg)
111
111
  * - CONFLICT (removed because it conflicts with in-block transaction)
112
- * - REPLACED (removed due to RBF replacement)
113
112
  *
114
113
  * This does not fire for transactions that are removed from the mempool
115
114
  * because they have been included in a block. Any client that is interested
src/version.h CHANGED
@@ -9,13 +9,14 @@
9
9
  * network protocol versioning
10
10
  */
11
11
 
12
- static const int PROTOCOL_VERSION = 70016;
12
+ static const int PROTOCOL_VERSION = 70017;
13
+ static const int OLD_VERSION = 70014; // peercoin: used to communicate with clients that don't know how to send PoS information in headers
13
14
 
14
15
  //! initial proto version, to be increased after version/verack negotiation
15
16
  static const int INIT_PROTO_VERSION = 209;
16
17
 
17
18
  //! disconnect from peers older than this proto version
18
- static const int MIN_PEER_PROTO_VERSION = 31800;
19
+ static const int MIN_PEER_PROTO_VERSION = 70016;
19
20
 
20
21
  //! BIP 0031, pong message, is enabled for all versions AFTER this one
21
22
  static const int BIP0031_VERSION = 60000;
src/versionbits.cpp DELETED
@@ -1,246 +0,0 @@
1
- // Copyright (c) 2016-2021 The Bitcoin Core developers
2
- // Distributed under the MIT software license, see the accompanying
3
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
-
5
- #include <versionbits.h>
6
- #include <consensus/params.h>
7
-
8
- ThresholdState AbstractThresholdConditionChecker::GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
9
- {
10
- int nPeriod = Period(params);
11
- int nThreshold = Threshold(params);
12
- int min_activation_height = MinActivationHeight(params);
13
- int64_t nTimeStart = BeginTime(params);
14
- int64_t nTimeTimeout = EndTime(params);
15
-
16
- // Check if this deployment is always active.
17
- if (nTimeStart == Consensus::BIP9Deployment::ALWAYS_ACTIVE) {
18
- return ThresholdState::ACTIVE;
19
- }
20
-
21
- // Check if this deployment is never active.
22
- if (nTimeStart == Consensus::BIP9Deployment::NEVER_ACTIVE) {
23
- return ThresholdState::FAILED;
24
- }
25
-
26
- // A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.
27
- if (pindexPrev != nullptr) {
28
- pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
29
- }
30
-
31
- // Walk backwards in steps of nPeriod to find a pindexPrev whose information is known
32
- std::vector<const CBlockIndex*> vToCompute;
33
- while (cache.count(pindexPrev) == 0) {
34
- if (pindexPrev == nullptr) {
35
- // The genesis block is by definition defined.
36
- cache[pindexPrev] = ThresholdState::DEFINED;
37
- break;
38
- }
39
- if (pindexPrev->GetMedianTimePast() < nTimeStart) {
40
- // Optimization: don't recompute down further, as we know every earlier block will be before the start time
41
- cache[pindexPrev] = ThresholdState::DEFINED;
42
- break;
43
- }
44
- vToCompute.push_back(pindexPrev);
45
- pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
46
- }
47
-
48
- // At this point, cache[pindexPrev] is known
49
- assert(cache.count(pindexPrev));
50
- ThresholdState state = cache[pindexPrev];
51
-
52
- // Now walk forward and compute the state of descendants of pindexPrev
53
- while (!vToCompute.empty()) {
54
- ThresholdState stateNext = state;
55
- pindexPrev = vToCompute.back();
56
- vToCompute.pop_back();
57
-
58
- switch (state) {
59
- case ThresholdState::DEFINED: {
60
- if (pindexPrev->GetMedianTimePast() >= nTimeStart) {
61
- stateNext = ThresholdState::STARTED;
62
- }
63
- break;
64
- }
65
- case ThresholdState::STARTED: {
66
- // We need to count
67
- const CBlockIndex* pindexCount = pindexPrev;
68
- int count = 0;
69
- for (int i = 0; i < nPeriod; i++) {
70
- if (Condition(pindexCount, params)) {
71
- count++;
72
- }
73
- pindexCount = pindexCount->pprev;
74
- }
75
- if (count >= nThreshold) {
76
- stateNext = ThresholdState::LOCKED_IN;
77
- } else if (pindexPrev->GetMedianTimePast() >= nTimeTimeout) {
78
- stateNext = ThresholdState::FAILED;
79
- }
80
- break;
81
- }
82
- case ThresholdState::LOCKED_IN: {
83
- // Progresses into ACTIVE provided activation height will have been reached.
84
- if (pindexPrev->nHeight + 1 >= min_activation_height) {
85
- stateNext = ThresholdState::ACTIVE;
86
- }
87
- break;
88
- }
89
- case ThresholdState::FAILED:
90
- case ThresholdState::ACTIVE: {
91
- // Nothing happens, these are terminal states.
92
- break;
93
- }
94
- }
95
- cache[pindexPrev] = state = stateNext;
96
- }
97
-
98
- return state;
99
- }
100
-
101
- BIP9Stats AbstractThresholdConditionChecker::GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params, std::vector<bool>* signalling_blocks) const
102
- {
103
- BIP9Stats stats = {};
104
-
105
- stats.period = Period(params);
106
- stats.threshold = Threshold(params);
107
-
108
- if (pindex == nullptr) return stats;
109
-
110
- // Find how many blocks are in the current period
111
- int blocks_in_period = 1 + (pindex->nHeight % stats.period);
112
-
113
- // Reset signalling_blocks
114
- if (signalling_blocks) {
115
- signalling_blocks->assign(blocks_in_period, false);
116
- }
117
-
118
- // Count from current block to beginning of period
119
- int elapsed = 0;
120
- int count = 0;
121
- const CBlockIndex* currentIndex = pindex;
122
- do {
123
- ++elapsed;
124
- --blocks_in_period;
125
- if (Condition(currentIndex, params)) {
126
- ++count;
127
- if (signalling_blocks) signalling_blocks->at(blocks_in_period) = true;
128
- }
129
- currentIndex = currentIndex->pprev;
130
- } while(blocks_in_period > 0);
131
-
132
- stats.elapsed = elapsed;
133
- stats.count = count;
134
- stats.possible = (stats.period - stats.threshold ) >= (stats.elapsed - count);
135
-
136
- return stats;
137
- }
138
-
139
- int AbstractThresholdConditionChecker::GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const
140
- {
141
- int64_t start_time = BeginTime(params);
142
- if (start_time == Consensus::BIP9Deployment::ALWAYS_ACTIVE || start_time == Consensus::BIP9Deployment::NEVER_ACTIVE) {
143
- return 0;
144
- }
145
-
146
- const ThresholdState initialState = GetStateFor(pindexPrev, params, cache);
147
-
148
- // BIP 9 about state DEFINED: "The genesis block is by definition in this state for each deployment."
149
- if (initialState == ThresholdState::DEFINED) {
150
- return 0;
151
- }
152
-
153
- const int nPeriod = Period(params);
154
-
155
- // A block's state is always the same as that of the first of its period, so it is computed based on a pindexPrev whose height equals a multiple of nPeriod - 1.
156
- // To ease understanding of the following height calculation, it helps to remember that
157
- // right now pindexPrev points to the block prior to the block that we are computing for, thus:
158
- // if we are computing for the last block of a period, then pindexPrev points to the second to last block of the period, and
159
- // if we are computing for the first block of a period, then pindexPrev points to the last block of the previous period.
160
- // The parent of the genesis block is represented by nullptr.
161
- pindexPrev = pindexPrev->GetAncestor(pindexPrev->nHeight - ((pindexPrev->nHeight + 1) % nPeriod));
162
-
163
- const CBlockIndex* previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
164
-
165
- while (previousPeriodParent != nullptr && GetStateFor(previousPeriodParent, params, cache) == initialState) {
166
- pindexPrev = previousPeriodParent;
167
- previousPeriodParent = pindexPrev->GetAncestor(pindexPrev->nHeight - nPeriod);
168
- }
169
-
170
- // Adjust the result because right now we point to the parent block.
171
- return pindexPrev->nHeight + 1;
172
- }
173
-
174
- namespace
175
- {
176
- /**
177
- * Class to implement versionbits logic.
178
- */
179
- class VersionBitsConditionChecker : public AbstractThresholdConditionChecker {
180
- private:
181
- const Consensus::DeploymentPos id;
182
-
183
- protected:
184
- int64_t BeginTime(const Consensus::Params& params) const override { return params.vDeployments[id].nStartTime; }
185
- int64_t EndTime(const Consensus::Params& params) const override { return params.vDeployments[id].nTimeout; }
186
- int MinActivationHeight(const Consensus::Params& params) const override { return params.vDeployments[id].min_activation_height; }
187
- int Period(const Consensus::Params& params) const override { return params.nMinerConfirmationWindow; }
188
- int Threshold(const Consensus::Params& params) const override { return params.nRuleChangeActivationThreshold; }
189
-
190
- bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const override
191
- {
192
- return (((pindex->nVersion & VERSIONBITS_TOP_MASK) == VERSIONBITS_TOP_BITS) && (pindex->nVersion & Mask(params)) != 0);
193
- }
194
-
195
- public:
196
- explicit VersionBitsConditionChecker(Consensus::DeploymentPos id_) : id(id_) {}
197
- uint32_t Mask(const Consensus::Params& params) const { return ((uint32_t)1) << params.vDeployments[id].bit; }
198
- };
199
-
200
- } // namespace
201
-
202
- ThresholdState VersionBitsCache::State(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos)
203
- {
204
- LOCK(m_mutex);
205
- return VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, m_caches[pos]);
206
- }
207
-
208
- BIP9Stats VersionBitsCache::Statistics(const CBlockIndex* pindex, const Consensus::Params& params, Consensus::DeploymentPos pos, std::vector<bool>* signalling_blocks)
209
- {
210
- return VersionBitsConditionChecker(pos).GetStateStatisticsFor(pindex, params, signalling_blocks);
211
- }
212
-
213
- int VersionBitsCache::StateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos)
214
- {
215
- LOCK(m_mutex);
216
- return VersionBitsConditionChecker(pos).GetStateSinceHeightFor(pindexPrev, params, m_caches[pos]);
217
- }
218
-
219
- uint32_t VersionBitsCache::Mask(const Consensus::Params& params, Consensus::DeploymentPos pos)
220
- {
221
- return VersionBitsConditionChecker(pos).Mask(params);
222
- }
223
-
224
- int32_t VersionBitsCache::ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params)
225
- {
226
- LOCK(m_mutex);
227
- int32_t nVersion = VERSIONBITS_TOP_BITS;
228
-
229
- for (int i = 0; i < (int)Consensus::MAX_VERSION_BITS_DEPLOYMENTS; i++) {
230
- Consensus::DeploymentPos pos = static_cast<Consensus::DeploymentPos>(i);
231
- ThresholdState state = VersionBitsConditionChecker(pos).GetStateFor(pindexPrev, params, m_caches[pos]);
232
- if (state == ThresholdState::LOCKED_IN || state == ThresholdState::STARTED) {
233
- nVersion |= Mask(params, pos);
234
- }
235
- }
236
-
237
- return nVersion;
238
- }
239
-
240
- void VersionBitsCache::Clear()
241
- {
242
- LOCK(m_mutex);
243
- for (unsigned int d = 0; d < Consensus::MAX_VERSION_BITS_DEPLOYMENTS; d++) {
244
- m_caches[d].clear();
245
- }
246
- }
src/versionbits.h DELETED
@@ -1,107 +0,0 @@
1
- // Copyright (c) 2016-2021 The Bitcoin Core developers
2
- // Distributed under the MIT software license, see the accompanying
3
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
-
5
- #ifndef BITCOIN_VERSIONBITS_H
6
- #define BITCOIN_VERSIONBITS_H
7
-
8
- #include <chain.h>
9
- #include <sync.h>
10
-
11
- #include <map>
12
-
13
- /** What block version to use for new blocks (pre versionbits) */
14
- static const int32_t VERSIONBITS_LAST_OLD_BLOCK_VERSION = 4;
15
- /** What bits to set in version for versionbits blocks */
16
- static const int32_t VERSIONBITS_TOP_BITS = 0x20000000UL;
17
- /** What bitmask determines whether versionbits is in use */
18
- static const int32_t VERSIONBITS_TOP_MASK = 0xE0000000UL;
19
- /** Total bits available for versionbits */
20
- static const int32_t VERSIONBITS_NUM_BITS = 29;
21
-
22
- /** BIP 9 defines a finite-state-machine to deploy a softfork in multiple stages.
23
- * State transitions happen during retarget period if conditions are met
24
- * In case of reorg, transitions can go backward. Without transition, state is
25
- * inherited between periods. All blocks of a period share the same state.
26
- */
27
- enum class ThresholdState {
28
- DEFINED, // First state that each softfork starts out as. The genesis block is by definition in this state for each deployment.
29
- STARTED, // For blocks past the starttime.
30
- LOCKED_IN, // For at least one retarget period after the first retarget period with STARTED blocks of which at least threshold have the associated bit set in nVersion, until min_activation_height is reached.
31
- ACTIVE, // For all blocks after the LOCKED_IN retarget period (final state)
32
- FAILED, // For all blocks once the first retarget period after the timeout time is hit, if LOCKED_IN wasn't already reached (final state)
33
- };
34
-
35
- // A map that gives the state for blocks whose height is a multiple of Period().
36
- // The map is indexed by the block's parent, however, so all keys in the map
37
- // will either be nullptr or a block with (height + 1) % Period() == 0.
38
- typedef std::map<const CBlockIndex*, ThresholdState> ThresholdConditionCache;
39
-
40
- /** Display status of an in-progress BIP9 softfork */
41
- struct BIP9Stats {
42
- /** Length of blocks of the BIP9 signalling period */
43
- int period;
44
- /** Number of blocks with the version bit set required to activate the softfork */
45
- int threshold;
46
- /** Number of blocks elapsed since the beginning of the current period */
47
- int elapsed;
48
- /** Number of blocks with the version bit set since the beginning of the current period */
49
- int count;
50
- /** False if there are not enough blocks left in this period to pass activation threshold */
51
- bool possible;
52
- };
53
-
54
- /**
55
- * Abstract class that implements BIP9-style threshold logic, and caches results.
56
- */
57
- class AbstractThresholdConditionChecker {
58
- protected:
59
- virtual bool Condition(const CBlockIndex* pindex, const Consensus::Params& params) const =0;
60
- virtual int64_t BeginTime(const Consensus::Params& params) const =0;
61
- virtual int64_t EndTime(const Consensus::Params& params) const =0;
62
- virtual int MinActivationHeight(const Consensus::Params& params) const { return 0; }
63
- virtual int Period(const Consensus::Params& params) const =0;
64
- virtual int Threshold(const Consensus::Params& params) const =0;
65
-
66
- public:
67
- /** Returns the numerical statistics of an in-progress BIP9 softfork in the period including pindex
68
- * If provided, signalling_blocks is set to true/false based on whether each block in the period signalled
69
- */
70
- BIP9Stats GetStateStatisticsFor(const CBlockIndex* pindex, const Consensus::Params& params, std::vector<bool>* signalling_blocks = nullptr) const;
71
- /** Returns the state for pindex A based on parent pindexPrev B. Applies any state transition if conditions are present.
72
- * Caches state from first block of period. */
73
- ThresholdState GetStateFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const;
74
- /** Returns the height since when the ThresholdState has started for pindex A based on parent pindexPrev B, all blocks of a period share the same */
75
- int GetStateSinceHeightFor(const CBlockIndex* pindexPrev, const Consensus::Params& params, ThresholdConditionCache& cache) const;
76
- };
77
-
78
- /** BIP 9 allows multiple softforks to be deployed in parallel. We cache
79
- * per-period state for every one of them. */
80
- class VersionBitsCache
81
- {
82
- private:
83
- Mutex m_mutex;
84
- ThresholdConditionCache m_caches[Consensus::MAX_VERSION_BITS_DEPLOYMENTS] GUARDED_BY(m_mutex);
85
-
86
- public:
87
- /** Get the numerical statistics for a given deployment for the signalling period that includes pindex.
88
- * If provided, signalling_blocks is set to true/false based on whether each block in the period signalled
89
- */
90
- static BIP9Stats Statistics(const CBlockIndex* pindex, const Consensus::Params& params, Consensus::DeploymentPos pos, std::vector<bool>* signalling_blocks = nullptr);
91
-
92
- static uint32_t Mask(const Consensus::Params& params, Consensus::DeploymentPos pos);
93
-
94
- /** Get the BIP9 state for a given deployment for the block after pindexPrev. */
95
- ThresholdState State(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos);
96
-
97
- /** Get the block height at which the BIP9 deployment switched into the state for the block after pindexPrev. */
98
- int StateSinceHeight(const CBlockIndex* pindexPrev, const Consensus::Params& params, Consensus::DeploymentPos pos);
99
-
100
- /** Determine what nVersion a new block should use
101
- */
102
- int32_t ComputeBlockVersion(const CBlockIndex* pindexPrev, const Consensus::Params& params);
103
-
104
- void Clear();
105
- };
106
-
107
- #endif // BITCOIN_VERSIONBITS_H
src/wallet/coincontrol.h CHANGED
@@ -6,8 +6,6 @@
6
6
  #define BITCOIN_WALLET_COINCONTROL_H
7
7
 
8
8
  #include <outputtype.h>
9
- #include <policy/feerate.h>
10
- #include <policy/fees.h>
11
9
  #include <primitives/transaction.h>
12
10
  #include <script/keyorigin.h>
13
11
  #include <script/signingprovider.h>
@@ -41,20 +39,12 @@ public:
41
39
  bool fAllowOtherInputs = false;
42
40
  //! Includes watch only addresses which are solvable
43
41
  bool fAllowWatchOnly = false;
44
- //! Override automatic min/max checks on fee, m_feerate must be set if true
45
- bool fOverrideFeeRate = false;
46
- //! Override the wallet's m_pay_tx_fee if set
47
- std::optional<CFeeRate> m_feerate;
48
42
  //! Override the default confirmation target if set
49
43
  std::optional<unsigned int> m_confirm_target;
50
- //! Override the wallet's m_signal_rbf if set
51
- std::optional<bool> m_signal_bip125_rbf;
52
44
  //! Avoid partial use of funds sent to a given address
53
45
  bool m_avoid_partial_spends = DEFAULT_AVOIDPARTIALSPENDS;
54
46
  //! Forbids inclusion of dirty (previously used) addresses
55
47
  bool m_avoid_address_reuse = false;
56
- //! Fee estimation mode to control arguments to estimateSmartFee
57
- FeeEstimateMode m_fee_mode = FeeEstimateMode::UNSET;
58
48
  //! Minimum chain depth value for coin availability
59
49
  int m_min_depth = DEFAULT_MIN_DEPTH;
60
50
  //! Maximum chain depth value for coin availability
src/wallet/coinselection.cpp CHANGED
@@ -5,7 +5,8 @@
5
5
  #include <wallet/coinselection.h>
6
6
 
7
7
  #include <consensus/amount.h>
8
- #include <policy/feerate.h>
8
+ #include <consensus/tx_verify.h>
9
+ #include <timedata.h>
9
10
  #include <util/check.h>
10
11
  #include <util/system.h>
11
12
  #include <util/moneystr.h>
@@ -94,7 +95,7 @@ std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_poo
94
95
  bool backtrack = false;
95
96
  if (curr_value + curr_available_value < selection_target || // Cannot possibly reach target with the amount remaining in the curr_available_value.
96
97
  curr_value > selection_target + cost_of_change || // Selected value is out of range, go back and try other branch
97
- (curr_waste > best_waste && (utxo_pool.at(0).fee - utxo_pool.at(0).long_term_fee) > 0)) { // Don't select things which we know will be more wasteful if the waste is increasing
98
+ (curr_waste > best_waste)) { // Don't select things which we know will be more wasteful if the waste is increasing
98
99
  backtrack = true;
99
100
  } else if (curr_value >= selection_target) { // Selected value is within range
100
101
  curr_waste += (curr_value - selection_target); // This is the excess value which is added to the waste for the below comparison
@@ -130,7 +131,7 @@ std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_poo
130
131
  curr_selection.back() = false;
131
132
  OutputGroup& utxo = utxo_pool.at(curr_selection.size() - 1);
132
133
  curr_value -= utxo.GetSelectionAmount();
133
- curr_waste -= utxo.fee - utxo.long_term_fee;
134
+ curr_waste -= utxo.fee;
134
135
  } else { // Moving forwards, continuing down this branch
135
136
  OutputGroup& utxo = utxo_pool.at(curr_selection.size());
136
137
 
@@ -147,7 +148,7 @@ std::optional<SelectionResult> SelectCoinsBnB(std::vector<OutputGroup>& utxo_poo
147
148
  // Inclusion branch first (Largest First Exploration)
148
149
  curr_selection.push_back(true);
149
150
  curr_value += utxo.GetSelectionAmount();
150
- curr_waste += utxo.fee - utxo.long_term_fee;
151
+ curr_waste += utxo.fee;
151
152
  }
152
153
  }
153
154
  }
@@ -250,7 +251,7 @@ std::optional<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups,
250
251
  if (group.GetSelectionAmount() == nTargetValue) {
251
252
  result.AddInput(group);
252
253
  return result;
253
- } else if (group.GetSelectionAmount() < nTargetValue + MIN_CHANGE) {
254
+ } else if (group.GetSelectionAmount() < nTargetValue + MIN_TXOUT_AMOUNT) {
254
255
  applicable_groups.push_back(group);
255
256
  nTotalLower += group.GetSelectionAmount();
256
257
  } else if (!lowest_larger || group.GetSelectionAmount() < lowest_larger->GetSelectionAmount()) {
@@ -277,14 +278,14 @@ std::optional<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups,
277
278
  CAmount nBest;
278
279
 
279
280
  ApproximateBestSubset(applicable_groups, nTotalLower, nTargetValue, vfBest, nBest);
280
- if (nBest != nTargetValue && nTotalLower >= nTargetValue + MIN_CHANGE) {
281
- ApproximateBestSubset(applicable_groups, nTotalLower, nTargetValue + MIN_CHANGE, vfBest, nBest);
281
+ if (nBest != nTargetValue && nTotalLower >= nTargetValue + MIN_TXOUT_AMOUNT) {
282
+ ApproximateBestSubset(applicable_groups, nTotalLower, nTargetValue + MIN_TXOUT_AMOUNT, vfBest, nBest);
282
283
  }
283
284
 
284
285
  // If we have a bigger coin and (either the stochastic approximation didn't find a good solution,
285
286
  // or the next bigger coin is closer), return the bigger coin
286
287
  if (lowest_larger &&
287
- ((nBest != nTargetValue && nBest < nTargetValue + MIN_CHANGE) || lowest_larger->GetSelectionAmount() <= nBest)) {
288
+ ((nBest != nTargetValue && nBest < nTargetValue + MIN_TXOUT_AMOUNT) || lowest_larger->GetSelectionAmount() <= nBest)) {
288
289
  result.AddInput(*lowest_larger);
289
290
  } else {
290
291
  for (unsigned int i = 0; i < applicable_groups.size(); i++) {
@@ -315,7 +316,7 @@ std::optional<SelectionResult> KnapsackSolver(std::vector<OutputGroup>& groups,
315
316
 
316
317
  void OutputGroup::Insert(const CInputCoin& output, int depth, bool from_me, size_t ancestors, size_t descendants, bool positive_only) {
317
318
  // Compute the effective value first
318
- const CAmount coin_fee = output.m_input_bytes < 0 ? 0 : m_effective_feerate.GetFee(output.m_input_bytes);
319
+ const CAmount coin_fee = output.m_input_bytes < 0 ? 0 : GetMinFee(output.m_input_bytes, GetAdjustedTime());
319
320
  const CAmount ev = output.txout.nValue - coin_fee;
320
321
 
321
322
  // Filter for positive only here before adding the coin
@@ -327,8 +328,7 @@ void OutputGroup::Insert(const CInputCoin& output, int depth, bool from_me, size
327
328
  coin.m_fee = coin_fee;
328
329
  fee += coin.m_fee;
329
330
 
330
- coin.m_long_term_fee = coin.m_input_bytes < 0 ? 0 : m_long_term_feerate.GetFee(coin.m_input_bytes);
331
- long_term_fee += coin.m_long_term_fee;
331
+ coin.m_long_term_fee = coin.m_input_bytes < 0 ? 0 : GetMinFee(output.m_input_bytes, GetAdjustedTime());
332
332
 
333
333
  coin.effective_value = ev;
334
334
  effective_value += coin.effective_value;
src/wallet/coinselection.h CHANGED
@@ -6,17 +6,14 @@
6
6
  #define BITCOIN_WALLET_COINSELECTION_H
7
7
 
8
8
  #include <consensus/amount.h>
9
- #include <policy/feerate.h>
10
9
  #include <primitives/transaction.h>
11
10
  #include <random.h>
12
11
 
13
12
  #include <optional>
14
13
 
15
14
  namespace wallet {
16
- //! target minimum change amount
17
- static constexpr CAmount MIN_CHANGE{COIN / 100};
18
15
  //! final minimum change amount after paying for fees
19
- static const CAmount MIN_FINAL_CHANGE = MIN_CHANGE/2;
16
+ static const CAmount MIN_FINAL_CHANGE = MIN_TXOUT_AMOUNT;
20
17
 
21
18
  /** A UTXO under consideration for use in funding a new transaction. */
22
19
  class CInputCoin {
@@ -83,13 +80,6 @@ struct CoinSelectionParams
83
80
  CAmount m_change_fee{0};
84
81
  /** Cost of creating the change output + cost of spending the change output in the future. */
85
82
  CAmount m_cost_of_change{0};
86
- /** The targeted feerate of the transaction being built. */
87
- CFeeRate m_effective_feerate;
88
- /** The feerate estimate used to estimate an upper bound on what should be sufficient to spend
89
- * the change output sometime in the future. */
90
- CFeeRate m_long_term_feerate;
91
- /** If the cost to spend a change output at the discard feerate exceeds its value, drop it to fees. */
92
- CFeeRate m_discard_feerate;
93
83
  /** Size of the transaction before coin selection, consisting of the header and recipient
94
84
  * output(s), excluding the inputs and change output(s). */
95
85
  size_t tx_noinputs_size = 0;
@@ -100,13 +90,10 @@ struct CoinSelectionParams
100
90
  * reuse. Dust outputs are not eligible to be added to output groups and thus not considered. */
101
91
  bool m_avoid_partial_spends = false;
102
92
 
103
- CoinSelectionParams(size_t change_output_size, size_t change_spend_size, CFeeRate effective_feerate,
104
- CFeeRate long_term_feerate, CFeeRate discard_feerate, size_t tx_noinputs_size, bool avoid_partial) :
93
+ CoinSelectionParams(size_t change_output_size, size_t change_spend_size,
94
+ size_t tx_noinputs_size, bool avoid_partial) :
105
95
  change_output_size(change_output_size),
106
96
  change_spend_size(change_spend_size),
107
- m_effective_feerate(effective_feerate),
108
- m_long_term_feerate(long_term_feerate),
109
- m_discard_feerate(discard_feerate),
110
97
  tx_noinputs_size(tx_noinputs_size),
111
98
  m_avoid_partial_spends(avoid_partial)
112
99
  {}
@@ -157,22 +144,12 @@ struct OutputGroup
157
144
  CAmount effective_value{0};
158
145
  /** The fee to spend these UTXOs at the effective feerate. */
159
146
  CAmount fee{0};
160
- /** The target feerate of the transaction we're trying to build. */
161
- CFeeRate m_effective_feerate{0};
162
- /** The fee to spend these UTXOs at the long term feerate. */
163
- CAmount long_term_fee{0};
164
- /** The feerate for spending a created change output eventually (i.e. not urgently, and thus at
165
- * a lower feerate). Calculated using long term fee estimate. This is used to decide whether
166
- * it could be economical to create a change output. */
167
- CFeeRate m_long_term_feerate{0};
168
147
  /** Indicate that we are subtracting the fee from outputs.
169
148
  * When true, the value that is used for coin selection is the UTXO's real value rather than effective value */
170
149
  bool m_subtract_fee_outputs{false};
171
150
 
172
151
  OutputGroup() {}
173
152
  OutputGroup(const CoinSelectionParams& params) :
174
- m_effective_feerate(params.m_effective_feerate),
175
- m_long_term_feerate(params.m_long_term_feerate),
176
153
  m_subtract_fee_outputs(params.m_subtract_fee_outputs)
177
154
  {}
178
155
 
src/wallet/feebumper.cpp DELETED
@@ -1,286 +0,0 @@
1
- // Copyright (c) 2017-2021 The Bitcoin Core developers
2
- // Distributed under the MIT software license, see the accompanying
3
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
-
5
- #include <interfaces/chain.h>
6
- #include <policy/fees.h>
7
- #include <policy/policy.h>
8
- #include <util/moneystr.h>
9
- #include <util/rbf.h>
10
- #include <util/system.h>
11
- #include <util/translation.h>
12
- #include <wallet/coincontrol.h>
13
- #include <wallet/feebumper.h>
14
- #include <wallet/fees.h>
15
- #include <wallet/receive.h>
16
- #include <wallet/spend.h>
17
- #include <wallet/wallet.h>
18
-
19
- namespace wallet {
20
- //! Check whether transaction has descendant in wallet or mempool, or has been
21
- //! mined, or conflicts with a mined transaction. Return a feebumper::Result.
22
- static feebumper::Result PreconditionChecks(const CWallet& wallet, const CWalletTx& wtx, std::vector<bilingual_str>& errors) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
23
- {
24
- if (wallet.HasWalletSpend(wtx.GetHash())) {
25
- errors.push_back(Untranslated("Transaction has descendants in the wallet"));
26
- return feebumper::Result::INVALID_PARAMETER;
27
- }
28
-
29
- {
30
- if (wallet.chain().hasDescendantsInMempool(wtx.GetHash())) {
31
- errors.push_back(Untranslated("Transaction has descendants in the mempool"));
32
- return feebumper::Result::INVALID_PARAMETER;
33
- }
34
- }
35
-
36
- if (wallet.GetTxDepthInMainChain(wtx) != 0) {
37
- errors.push_back(Untranslated("Transaction has been mined, or is conflicted with a mined transaction"));
38
- return feebumper::Result::WALLET_ERROR;
39
- }
40
-
41
- if (!SignalsOptInRBF(*wtx.tx)) {
42
- errors.push_back(Untranslated("Transaction is not BIP 125 replaceable"));
43
- return feebumper::Result::WALLET_ERROR;
44
- }
45
-
46
- if (wtx.mapValue.count("replaced_by_txid")) {
47
- errors.push_back(strprintf(Untranslated("Cannot bump transaction %s which was already bumped by transaction %s"), wtx.GetHash().ToString(), wtx.mapValue.at("replaced_by_txid")));
48
- return feebumper::Result::WALLET_ERROR;
49
- }
50
-
51
- // check that original tx consists entirely of our inputs
52
- // if not, we can't bump the fee, because the wallet has no way of knowing the value of the other inputs (thus the fee)
53
- isminefilter filter = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE;
54
- if (!AllInputsMine(wallet, *wtx.tx, filter)) {
55
- errors.push_back(Untranslated("Transaction contains inputs that don't belong to this wallet"));
56
- return feebumper::Result::WALLET_ERROR;
57
- }
58
-
59
-
60
- return feebumper::Result::OK;
61
- }
62
-
63
- //! Check if the user provided a valid feeRate
64
- static feebumper::Result CheckFeeRate(const CWallet& wallet, const CWalletTx& wtx, const CFeeRate& newFeerate, const int64_t maxTxSize, std::vector<bilingual_str>& errors)
65
- {
66
- // check that fee rate is higher than mempool's minimum fee
67
- // (no point in bumping fee if we know that the new tx won't be accepted to the mempool)
68
- // This may occur if the user set fee_rate or paytxfee too low, if fallbackfee is too low, or, perhaps,
69
- // in a rare situation where the mempool minimum fee increased significantly since the fee estimation just a
70
- // moment earlier. In this case, we report an error to the user, who may adjust the fee.
71
- CFeeRate minMempoolFeeRate = wallet.chain().mempoolMinFee();
72
-
73
- if (newFeerate.GetFeePerK() < minMempoolFeeRate.GetFeePerK()) {
74
- errors.push_back(strprintf(
75
- Untranslated("New fee rate (%s) is lower than the minimum fee rate (%s) to get into the mempool -- "),
76
- FormatMoney(newFeerate.GetFeePerK()),
77
- FormatMoney(minMempoolFeeRate.GetFeePerK())));
78
- return feebumper::Result::WALLET_ERROR;
79
- }
80
-
81
- CAmount new_total_fee = newFeerate.GetFee(maxTxSize);
82
-
83
- CFeeRate incrementalRelayFee = std::max(wallet.chain().relayIncrementalFee(), CFeeRate(WALLET_INCREMENTAL_RELAY_FEE));
84
-
85
- // Given old total fee and transaction size, calculate the old feeRate
86
- isminefilter filter = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE;
87
- CAmount old_fee = CachedTxGetDebit(wallet, wtx, filter) - wtx.tx->GetValueOut();
88
- const int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
89
- CFeeRate nOldFeeRate(old_fee, txSize);
90
- // Min total fee is old fee + relay fee
91
- CAmount minTotalFee = nOldFeeRate.GetFee(maxTxSize) + incrementalRelayFee.GetFee(maxTxSize);
92
-
93
- if (new_total_fee < minTotalFee) {
94
- errors.push_back(strprintf(Untranslated("Insufficient total fee %s, must be at least %s (oldFee %s + incrementalFee %s)"),
95
- FormatMoney(new_total_fee), FormatMoney(minTotalFee), FormatMoney(nOldFeeRate.GetFee(maxTxSize)), FormatMoney(incrementalRelayFee.GetFee(maxTxSize))));
96
- return feebumper::Result::INVALID_PARAMETER;
97
- }
98
-
99
- CAmount requiredFee = GetRequiredFee(wallet, maxTxSize);
100
- if (new_total_fee < requiredFee) {
101
- errors.push_back(strprintf(Untranslated("Insufficient total fee (cannot be less than required fee %s)"),
102
- FormatMoney(requiredFee)));
103
- return feebumper::Result::INVALID_PARAMETER;
104
- }
105
-
106
- // Check that in all cases the new fee doesn't violate maxTxFee
107
- const CAmount max_tx_fee = wallet.m_default_max_tx_fee;
108
- if (new_total_fee > max_tx_fee) {
109
- errors.push_back(strprintf(Untranslated("Specified or calculated fee %s is too high (cannot be higher than -maxtxfee %s)"),
110
- FormatMoney(new_total_fee), FormatMoney(max_tx_fee)));
111
- return feebumper::Result::WALLET_ERROR;
112
- }
113
-
114
- return feebumper::Result::OK;
115
- }
116
-
117
- static CFeeRate EstimateFeeRate(const CWallet& wallet, const CWalletTx& wtx, const CAmount old_fee, const CCoinControl& coin_control)
118
- {
119
- // Get the fee rate of the original transaction. This is calculated from
120
- // the tx fee/vsize, so it may have been rounded down. Add 1 satoshi to the
121
- // result.
122
- int64_t txSize = GetVirtualTransactionSize(*(wtx.tx));
123
- CFeeRate feerate(old_fee, txSize);
124
- feerate += CFeeRate(1);
125
-
126
- // The node has a configurable incremental relay fee. Increment the fee by
127
- // the minimum of that and the wallet's conservative
128
- // WALLET_INCREMENTAL_RELAY_FEE value to future proof against changes to
129
- // network wide policy for incremental relay fee that our node may not be
130
- // aware of. This ensures we're over the required relay fee rate
131
- // (BIP 125 rule 4). The replacement tx will be at least as large as the
132
- // original tx, so the total fee will be greater (BIP 125 rule 3)
133
- CFeeRate node_incremental_relay_fee = wallet.chain().relayIncrementalFee();
134
- CFeeRate wallet_incremental_relay_fee = CFeeRate(WALLET_INCREMENTAL_RELAY_FEE);
135
- feerate += std::max(node_incremental_relay_fee, wallet_incremental_relay_fee);
136
-
137
- // Fee rate must also be at least the wallet's GetMinimumFeeRate
138
- CFeeRate min_feerate(GetMinimumFeeRate(wallet, coin_control, /* feeCalc */ nullptr));
139
-
140
- // Set the required fee rate for the replacement transaction in coin control.
141
- return std::max(feerate, min_feerate);
142
- }
143
-
144
- namespace feebumper {
145
-
146
- bool TransactionCanBeBumped(const CWallet& wallet, const uint256& txid)
147
- {
148
- LOCK(wallet.cs_wallet);
149
- const CWalletTx* wtx = wallet.GetWalletTx(txid);
150
- if (wtx == nullptr) return false;
151
-
152
- std::vector<bilingual_str> errors_dummy;
153
- feebumper::Result res = PreconditionChecks(wallet, *wtx, errors_dummy);
154
- return res == feebumper::Result::OK;
155
- }
156
-
157
- Result CreateRateBumpTransaction(CWallet& wallet, const uint256& txid, const CCoinControl& coin_control, std::vector<bilingual_str>& errors,
158
- CAmount& old_fee, CAmount& new_fee, CMutableTransaction& mtx)
159
- {
160
- // We are going to modify coin control later, copy to re-use
161
- CCoinControl new_coin_control(coin_control);
162
-
163
- LOCK(wallet.cs_wallet);
164
- errors.clear();
165
- auto it = wallet.mapWallet.find(txid);
166
- if (it == wallet.mapWallet.end()) {
167
- errors.push_back(Untranslated("Invalid or non-wallet transaction id"));
168
- return Result::INVALID_ADDRESS_OR_KEY;
169
- }
170
- const CWalletTx& wtx = it->second;
171
-
172
- Result result = PreconditionChecks(wallet, wtx, errors);
173
- if (result != Result::OK) {
174
- return result;
175
- }
176
-
177
- // Fill in recipients(and preserve a single change key if there is one)
178
- std::vector<CRecipient> recipients;
179
- for (const auto& output : wtx.tx->vout) {
180
- if (!OutputIsChange(wallet, output)) {
181
- CRecipient recipient = {output.scriptPubKey, output.nValue, false};
182
- recipients.push_back(recipient);
183
- } else {
184
- CTxDestination change_dest;
185
- ExtractDestination(output.scriptPubKey, change_dest);
186
- new_coin_control.destChange = change_dest;
187
- }
188
- }
189
-
190
- isminefilter filter = wallet.GetLegacyScriptPubKeyMan() && wallet.IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) ? ISMINE_WATCH_ONLY : ISMINE_SPENDABLE;
191
- old_fee = CachedTxGetDebit(wallet, wtx, filter) - wtx.tx->GetValueOut();
192
-
193
- if (coin_control.m_feerate) {
194
- // The user provided a feeRate argument.
195
- // We calculate this here to avoid compiler warning on the cs_wallet lock
196
- const int64_t maxTxSize{CalculateMaximumSignedTxSize(*wtx.tx, &wallet).vsize};
197
- Result res = CheckFeeRate(wallet, wtx, *new_coin_control.m_feerate, maxTxSize, errors);
198
- if (res != Result::OK) {
199
- return res;
200
- }
201
- } else {
202
- // The user did not provide a feeRate argument
203
- new_coin_control.m_feerate = EstimateFeeRate(wallet, wtx, old_fee, new_coin_control);
204
- }
205
-
206
- // Fill in required inputs we are double-spending(all of them)
207
- // N.B.: bip125 doesn't require all the inputs in the replaced transaction to be
208
- // used in the replacement transaction, but it's very important for wallets to make
209
- // sure that happens. If not, it would be possible to bump a transaction A twice to
210
- // A2 and A3 where A2 and A3 don't conflict (or alternatively bump A to A2 and A2
211
- // to A3 where A and A3 don't conflict). If both later get confirmed then the sender
212
- // has accidentally double paid.
213
- for (const auto& inputs : wtx.tx->vin) {
214
- new_coin_control.Select(COutPoint(inputs.prevout));
215
- }
216
- new_coin_control.fAllowOtherInputs = true;
217
-
218
- // We cannot source new unconfirmed inputs(bip125 rule 2)
219
- new_coin_control.m_min_depth = 1;
220
-
221
- CTransactionRef tx_new;
222
- CAmount fee_ret;
223
- int change_pos_in_out = -1; // No requested location for change
224
- bilingual_str fail_reason;
225
- FeeCalculation fee_calc_out;
226
- if (!CreateTransaction(wallet, recipients, tx_new, fee_ret, change_pos_in_out, fail_reason, new_coin_control, fee_calc_out, false)) {
227
- errors.push_back(Untranslated("Unable to create transaction.") + Untranslated(" ") + fail_reason);
228
- return Result::WALLET_ERROR;
229
- }
230
-
231
- // Write back new fee if successful
232
- new_fee = fee_ret;
233
-
234
- // Write back transaction
235
- mtx = CMutableTransaction(*tx_new);
236
- // Mark new tx not replaceable, if requested.
237
- if (!coin_control.m_signal_bip125_rbf.value_or(wallet.m_signal_rbf)) {
238
- for (auto& input : mtx.vin) {
239
- if (input.nSequence < 0xfffffffe) input.nSequence = 0xfffffffe;
240
- }
241
- }
242
-
243
- return Result::OK;
244
- }
245
-
246
- bool SignTransaction(CWallet& wallet, CMutableTransaction& mtx) {
247
- LOCK(wallet.cs_wallet);
248
- return wallet.SignTransaction(mtx);
249
- }
250
-
251
- Result CommitTransaction(CWallet& wallet, const uint256& txid, CMutableTransaction&& mtx, std::vector<bilingual_str>& errors, uint256& bumped_txid)
252
- {
253
- LOCK(wallet.cs_wallet);
254
- if (!errors.empty()) {
255
- return Result::MISC_ERROR;
256
- }
257
- auto it = txid.IsNull() ? wallet.mapWallet.end() : wallet.mapWallet.find(txid);
258
- if (it == wallet.mapWallet.end()) {
259
- errors.push_back(Untranslated("Invalid or non-wallet transaction id"));
260
- return Result::MISC_ERROR;
261
- }
262
- const CWalletTx& oldWtx = it->second;
263
-
264
- // make sure the transaction still has no descendants and hasn't been mined in the meantime
265
- Result result = PreconditionChecks(wallet, oldWtx, errors);
266
- if (result != Result::OK) {
267
- return result;
268
- }
269
-
270
- // commit/broadcast the tx
271
- CTransactionRef tx = MakeTransactionRef(std::move(mtx));
272
- mapValue_t mapValue = oldWtx.mapValue;
273
- mapValue["replaces_txid"] = oldWtx.GetHash().ToString();
274
-
275
- wallet.CommitTransaction(tx, std::move(mapValue), oldWtx.vOrderForm);
276
-
277
- // mark the original tx as bumped
278
- bumped_txid = tx->GetHash();
279
- if (!wallet.MarkReplaced(oldWtx.GetHash(), bumped_txid)) {
280
- errors.push_back(Untranslated("Created new bumpfee transaction but could not mark the original transaction as replaced"));
281
- }
282
- return Result::OK;
283
- }
284
-
285
- } // namespace feebumper
286
- } // namespace wallet
src/wallet/feebumper.h DELETED
@@ -1,61 +0,0 @@
1
- // Copyright (c) 2017-2020 The Bitcoin Core developers
2
- // Distributed under the MIT software license, see the accompanying
3
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
4
-
5
- #ifndef BITCOIN_WALLET_FEEBUMPER_H
6
- #define BITCOIN_WALLET_FEEBUMPER_H
7
-
8
- #include <primitives/transaction.h>
9
-
10
- class uint256;
11
- enum class FeeEstimateMode;
12
- struct bilingual_str;
13
-
14
- namespace wallet {
15
- class CCoinControl;
16
- class CWallet;
17
- class CWalletTx;
18
-
19
- namespace feebumper {
20
-
21
- enum class Result
22
- {
23
- OK,
24
- INVALID_ADDRESS_OR_KEY,
25
- INVALID_REQUEST,
26
- INVALID_PARAMETER,
27
- WALLET_ERROR,
28
- MISC_ERROR,
29
- };
30
-
31
- //! Return whether transaction can be bumped.
32
- bool TransactionCanBeBumped(const CWallet& wallet, const uint256& txid);
33
-
34
- //! Create bumpfee transaction based on feerate estimates.
35
- Result CreateRateBumpTransaction(CWallet& wallet,
36
- const uint256& txid,
37
- const CCoinControl& coin_control,
38
- std::vector<bilingual_str>& errors,
39
- CAmount& old_fee,
40
- CAmount& new_fee,
41
- CMutableTransaction& mtx);
42
-
43
- //! Sign the new transaction,
44
- //! @return false if the tx couldn't be found or if it was
45
- //! impossible to create the signature(s)
46
- bool SignTransaction(CWallet& wallet, CMutableTransaction& mtx);
47
-
48
- //! Commit the bumpfee transaction.
49
- //! @return success in case of CWallet::CommitTransaction was successful,
50
- //! but sets errors if the tx could not be added to the mempool (will try later)
51
- //! or if the old transaction could not be marked as replaced.
52
- Result CommitTransaction(CWallet& wallet,
53
- const uint256& txid,
54
- CMutableTransaction&& mtx,
55
- std::vector<bilingual_str>& errors,
56
- uint256& bumped_txid);
57
-
58
- } // namespace feebumper
59
- } // namespace wallet
60
-
61
- #endif // BITCOIN_WALLET_FEEBUMPER_H
src/wallet/fees.cpp DELETED
@@ -1,94 +0,0 @@
1
- // Copyright (c) 2009-2010 Satoshi Nakamoto
2
- // Copyright (c) 2009-2020 The Bitcoin Core developers
3
- // Distributed under the MIT software license, see the accompanying
4
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
-
6
- #include <wallet/fees.h>
7
-
8
- #include <wallet/coincontrol.h>
9
- #include <wallet/wallet.h>
10
-
11
-
12
- namespace wallet {
13
- CAmount GetRequiredFee(const CWallet& wallet, unsigned int nTxBytes)
14
- {
15
- return GetRequiredFeeRate(wallet).GetFee(nTxBytes);
16
- }
17
-
18
-
19
- CAmount GetMinimumFee(const CWallet& wallet, unsigned int nTxBytes, const CCoinControl& coin_control, FeeCalculation* feeCalc)
20
- {
21
- return GetMinimumFeeRate(wallet, coin_control, feeCalc).GetFee(nTxBytes);
22
- }
23
-
24
- CFeeRate GetRequiredFeeRate(const CWallet& wallet)
25
- {
26
- return std::max(wallet.m_min_fee, wallet.chain().relayMinFee());
27
- }
28
-
29
- CFeeRate GetMinimumFeeRate(const CWallet& wallet, const CCoinControl& coin_control, FeeCalculation* feeCalc)
30
- {
31
- /* User control of how to calculate fee uses the following parameter precedence:
32
- 1. coin_control.m_feerate
33
- 2. coin_control.m_confirm_target
34
- 3. m_pay_tx_fee (user-set member variable of wallet)
35
- 4. m_confirm_target (user-set member variable of wallet)
36
- The first parameter that is set is used.
37
- */
38
- CFeeRate feerate_needed;
39
- if (coin_control.m_feerate) { // 1.
40
- feerate_needed = *(coin_control.m_feerate);
41
- if (feeCalc) feeCalc->reason = FeeReason::PAYTXFEE;
42
- // Allow to override automatic min/max check over coin control instance
43
- if (coin_control.fOverrideFeeRate) return feerate_needed;
44
- }
45
- else if (!coin_control.m_confirm_target && wallet.m_pay_tx_fee != CFeeRate(0)) { // 3. TODO: remove magic value of 0 for wallet member m_pay_tx_fee
46
- feerate_needed = wallet.m_pay_tx_fee;
47
- if (feeCalc) feeCalc->reason = FeeReason::PAYTXFEE;
48
- }
49
- else { // 2. or 4.
50
- // We will use smart fee estimation
51
- unsigned int target = coin_control.m_confirm_target ? *coin_control.m_confirm_target : wallet.m_confirm_target;
52
- // By default estimates are economical iff we are signaling opt-in-RBF
53
- bool conservative_estimate = !coin_control.m_signal_bip125_rbf.value_or(wallet.m_signal_rbf);
54
- // Allow to override the default fee estimate mode over the CoinControl instance
55
- if (coin_control.m_fee_mode == FeeEstimateMode::CONSERVATIVE) conservative_estimate = true;
56
- else if (coin_control.m_fee_mode == FeeEstimateMode::ECONOMICAL) conservative_estimate = false;
57
-
58
- feerate_needed = wallet.chain().estimateSmartFee(target, conservative_estimate, feeCalc);
59
- if (feerate_needed == CFeeRate(0)) {
60
- // if we don't have enough data for estimateSmartFee, then use fallback fee
61
- feerate_needed = wallet.m_fallback_fee;
62
- if (feeCalc) feeCalc->reason = FeeReason::FALLBACK;
63
-
64
- // directly return if fallback fee is disabled (feerate 0 == disabled)
65
- if (wallet.m_fallback_fee == CFeeRate(0)) return feerate_needed;
66
- }
67
- // Obey mempool min fee when using smart fee estimation
68
- CFeeRate min_mempool_feerate = wallet.chain().mempoolMinFee();
69
- if (feerate_needed < min_mempool_feerate) {
70
- feerate_needed = min_mempool_feerate;
71
- if (feeCalc) feeCalc->reason = FeeReason::MEMPOOL_MIN;
72
- }
73
- }
74
-
75
- // prevent user from paying a fee below the required fee rate
76
- CFeeRate required_feerate = GetRequiredFeeRate(wallet);
77
- if (required_feerate > feerate_needed) {
78
- feerate_needed = required_feerate;
79
- if (feeCalc) feeCalc->reason = FeeReason::REQUIRED;
80
- }
81
- return feerate_needed;
82
- }
83
-
84
- CFeeRate GetDiscardRate(const CWallet& wallet)
85
- {
86
- unsigned int highest_target = wallet.chain().estimateMaxBlocks();
87
- CFeeRate discard_rate = wallet.chain().estimateSmartFee(highest_target, false /* conservative */);
88
- // Don't let discard_rate be greater than longest possible fee estimate if we get a valid fee estimate
89
- discard_rate = (discard_rate == CFeeRate(0)) ? wallet.m_discard_rate : std::min(discard_rate, wallet.m_discard_rate);
90
- // Discard rate must be at least dustRelayFee
91
- discard_rate = std::max(discard_rate, wallet.chain().relayDustFee());
92
- return discard_rate;
93
- }
94
- } // namespace wallet
src/wallet/fees.h DELETED
@@ -1,48 +0,0 @@
1
- // Copyright (c) 2009-2010 Satoshi Nakamoto
2
- // Copyright (c) 2009-2021 The Bitcoin Core developers
3
- // Distributed under the MIT software license, see the accompanying
4
- // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
-
6
- #ifndef BITCOIN_WALLET_FEES_H
7
- #define BITCOIN_WALLET_FEES_H
8
-
9
- #include <consensus/amount.h>
10
-
11
- class CFeeRate;
12
- struct FeeCalculation;
13
-
14
- namespace wallet {
15
- class CCoinControl;
16
- class CWallet;
17
-
18
- /**
19
- * Return the minimum required absolute fee for this size
20
- * based on the required fee rate
21
- */
22
- CAmount GetRequiredFee(const CWallet& wallet, unsigned int nTxBytes);
23
-
24
- /**
25
- * Estimate the minimum fee considering user set parameters
26
- * and the required fee
27
- */
28
- CAmount GetMinimumFee(const CWallet& wallet, unsigned int nTxBytes, const CCoinControl& coin_control, FeeCalculation* feeCalc);
29
-
30
- /**
31
- * Return the minimum required feerate taking into account the
32
- * minimum relay feerate and user set minimum transaction feerate
33
- */
34
- CFeeRate GetRequiredFeeRate(const CWallet& wallet);
35
-
36
- /**
37
- * Estimate the minimum fee rate considering user set parameters
38
- * and the required fee
39
- */
40
- CFeeRate GetMinimumFeeRate(const CWallet& wallet, const CCoinControl& coin_control, FeeCalculation* feeCalc);
41
-
42
- /**
43
- * Return the maximum feerate for discarding change.
44
- */
45
- CFeeRate GetDiscardRate(const CWallet& wallet);
46
- } // namespace wallet
47
-
48
- #endif // BITCOIN_WALLET_FEES_H
src/wallet/init.cpp CHANGED
@@ -52,32 +52,18 @@ void WalletInit::AddWalletOptions(ArgsManager& argsman) const
52
52
  ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
53
53
  argsman.AddArg("-consolidatefeerate=<amt>", strprintf("The maximum feerate (in %s/kvB) at which transaction building may use more inputs than strictly necessary so that the wallet's UTXO pool can be reduced (default: %s).", CURRENCY_UNIT, FormatMoney(DEFAULT_CONSOLIDATE_FEERATE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
54
54
  argsman.AddArg("-disablewallet", "Do not load the wallet and disable wallet RPC calls", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
55
- argsman.AddArg("-discardfee=<amt>", strprintf("The fee rate (in %s/kvB) that indicates your tolerance for discarding change by adding it to the fee (default: %s). "
56
- "Note: An output is discarded if it is dust at this rate, but we will always discard up to the dust relay fee and a discard fee above that is limited by the fee estimate for the longest target",
57
- CURRENCY_UNIT, FormatMoney(DEFAULT_DISCARD_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
58
-
59
- argsman.AddArg("-fallbackfee=<amt>", strprintf("A fee rate (in %s/kvB) that will be used when fee estimation has insufficient data. 0 to entirely disable the fallbackfee feature. (default: %s)",
60
- CURRENCY_UNIT, FormatMoney(DEFAULT_FALLBACK_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
61
55
  argsman.AddArg("-keypool=<n>", strprintf("Set key pool size to <n> (default: %u). Warning: Smaller sizes may increase the risk of losing funds when restoring from an old backup, if none of the addresses in the original keypool have been used.", DEFAULT_KEYPOOL_SIZE), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
62
- argsman.AddArg("-maxapsfee=<n>", strprintf("Spend up to this amount in additional (absolute) fees (in %s) if it allows the use of partial spend avoidance (default: %s)", CURRENCY_UNIT, FormatMoney(DEFAULT_MAX_AVOIDPARTIALSPEND_FEE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
63
- argsman.AddArg("-maxtxfee=<amt>", strprintf("Maximum total fees (in %s) to use in a single wallet transaction; setting this too low may abort large transactions (default: %s)",
64
- CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MAXFEE)), ArgsManager::ALLOW_ANY, OptionsCategory::DEBUG_TEST);
65
- argsman.AddArg("-mintxfee=<amt>", strprintf("Fee rates (in %s/kvB) smaller than this are considered zero fee for transaction creation (default: %s)",
66
- CURRENCY_UNIT, FormatMoney(DEFAULT_TRANSACTION_MINFEE)), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
67
- argsman.AddArg("-paytxfee=<amt>", strprintf("Fee rate (in %s/kvB) to add to transactions you send (default: %s)",
68
- CURRENCY_UNIT, FormatMoney(CFeeRate{DEFAULT_PAY_TX_FEE}.GetFeePerK())), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
56
+ argsman.AddArg("-minting", "Mint proof of stake blocks", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
69
57
  #ifdef ENABLE_EXTERNAL_SIGNER
70
58
  argsman.AddArg("-signer=<cmd>", "External signing tool, see doc/external-signer.md", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
71
59
  #endif
72
60
  argsman.AddArg("-spendzeroconfchange", strprintf("Spend unconfirmed change when sending transactions (default: %u)", DEFAULT_SPEND_ZEROCONF_CHANGE), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
73
- argsman.AddArg("-txconfirmtarget=<n>", strprintf("If paytxfee is not set, include enough fee so transactions begin confirmation on average within n blocks (default: %u)", DEFAULT_TX_CONFIRM_TARGET), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
74
61
  argsman.AddArg("-wallet=<path>", "Specify wallet path to load at startup. Can be used multiple times to load multiple wallets. Path is to a directory containing wallet data and log files. If the path is not absolute, it is interpreted relative to <walletdir>. This only loads existing wallets and does not create new ones. For backwards compatibility this also accepts names of existing top-level data files in <walletdir>.", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET);
75
62
  argsman.AddArg("-walletbroadcast", strprintf("Make the wallet broadcast transactions (default: %u)", DEFAULT_WALLETBROADCAST), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
76
63
  argsman.AddArg("-walletdir=<dir>", "Specify directory to hold wallets (default: <datadir>/wallets if it exists, otherwise <datadir>)", ArgsManager::ALLOW_ANY | ArgsManager::NETWORK_ONLY, OptionsCategory::WALLET);
77
64
  #if HAVE_SYSTEM
78
65
  argsman.AddArg("-walletnotify=<cmd>", "Execute command when a wallet transaction changes. %s in cmd is replaced by TxID, %w is replaced by wallet name, %b is replaced by the hash of the block including the transaction (set to 'unconfirmed' if the transaction is not included) and %h is replaced by the block height (-1 if not included). %w is not currently implemented on windows. On systems where %w is supported, it should NOT be quoted because this would break shell escaping used to invoke the command.", ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
79
66
  #endif
80
- argsman.AddArg("-walletrbf", strprintf("Send transactions with full-RBF opt-in enabled (RPC only, default: %u)", DEFAULT_WALLET_RBF), ArgsManager::ALLOW_ANY, OptionsCategory::WALLET);
81
67
 
82
68
  #ifdef USE_BDB
83
69
  argsman.AddArg("-dblogsize=<n>", strprintf("Flush wallet database activity from memory to disk log every <n> megabytes (default: %u)", DEFAULT_WALLET_DBLOGSIZE), ArgsManager::ALLOW_ANY | ArgsManager::DEBUG_ONLY, OptionsCategory::WALLET_DEBUG_TEST);
@@ -123,6 +109,12 @@ bool WalletInit::ParameterInteraction() const
123
109
 
124
110
  if (gArgs.GetBoolArg("-sysperms", false))
125
111
  return InitError(Untranslated("-sysperms is not allowed in combination with enabled wallet functionality"));
112
+ if (gArgs.IsArgSet("-reservebalance"))
113
+ {
114
+ std::optional<CAmount> nReserveBalance = ParseMoney(gArgs.GetArg("-reservebalance", ""));
115
+ if (!nReserveBalance)
116
+ return InitError(Untranslated(strprintf("Invalid amount for -reservebalance=<amount>: '%s'", gArgs.GetArg("-reservebalance", ""))));
117
+ }
126
118
 
127
119
  return true;
128
120
  }
src/wallet/interfaces.cpp CHANGED
@@ -7,7 +7,6 @@
7
7
  #include <consensus/amount.h>
8
8
  #include <interfaces/chain.h>
9
9
  #include <interfaces/handler.h>
10
- #include <policy/fees.h>
11
10
  #include <primitives/transaction.h>
12
11
  #include <rpc/server.h>
13
12
  #include <script/standard.h>
@@ -19,8 +18,6 @@
19
18
  #include <util/translation.h>
20
19
  #include <util/ui_change_type.h>
21
20
  #include <wallet/context.h>
22
- #include <wallet/feebumper.h>
23
- #include <wallet/fees.h>
24
21
  #include <wallet/ismine.h>
25
22
  #include <wallet/load.h>
26
23
  #include <wallet/receive.h>
@@ -75,6 +72,7 @@ WalletTx MakeWalletTx(CWallet& wallet, const CWalletTx& wtx)
75
72
  result.time = wtx.GetTxTime();
76
73
  result.value_map = wtx.mapValue;
77
74
  result.is_coinbase = wtx.IsCoinBase();
75
+ result.is_coinstake = wtx.IsCoinStake();
78
76
  return result;
79
77
  }
80
78
 
@@ -93,6 +91,7 @@ WalletTxStatus MakeWalletTxStatus(const CWallet& wallet, const CWalletTx& wtx)
93
91
  result.is_trusted = CachedTxIsTrusted(wallet, wtx);
94
92
  result.is_abandoned = wtx.isAbandoned();
95
93
  result.is_coinbase = wtx.IsCoinBase();
94
+ result.is_coinstake = wtx.IsCoinStake();
96
95
  result.is_in_main_chain = wallet.IsTxInMainChain(wtx);
97
96
  return result;
98
97
  }
@@ -247,7 +246,7 @@ public:
247
246
  {
248
247
  LOCK(m_wallet->cs_wallet);
249
248
  CTransactionRef tx;
250
- FeeCalculation fee_calc_out;
249
+ CAmount fee_calc_out;
251
250
  if (!CreateTransaction(*m_wallet, recipients, tx, fee, change_pos,
252
251
  fail_reason, coin_control, fee_calc_out, sign)) {
253
252
  return {};
@@ -267,28 +266,6 @@ public:
267
266
  LOCK(m_wallet->cs_wallet);
268
267
  return m_wallet->AbandonTransaction(txid);
269
268
  }
270
- bool transactionCanBeBumped(const uint256& txid) override
271
- {
272
- return feebumper::TransactionCanBeBumped(*m_wallet.get(), txid);
273
- }
274
- bool createBumpTransaction(const uint256& txid,
275
- const CCoinControl& coin_control,
276
- std::vector<bilingual_str>& errors,
277
- CAmount& old_fee,
278
- CAmount& new_fee,
279
- CMutableTransaction& mtx) override
280
- {
281
- return feebumper::CreateRateBumpTransaction(*m_wallet.get(), txid, coin_control, errors, old_fee, new_fee, mtx) == feebumper::Result::OK;
282
- }
283
- bool signBumpTransaction(CMutableTransaction& mtx) override { return feebumper::SignTransaction(*m_wallet.get(), mtx); }
284
- bool commitBumpTransaction(const uint256& txid,
285
- CMutableTransaction&& mtx,
286
- std::vector<bilingual_str>& errors,
287
- uint256& bumped_txid) override
288
- {
289
- return feebumper::CommitTransaction(*m_wallet.get(), txid, std::move(mtx), errors, bumped_txid) ==
290
- feebumper::Result::OK;
291
- }
292
269
  CTransactionRef getTx(const uint256& txid) override
293
270
  {
294
271
  LOCK(m_wallet->cs_wallet);
@@ -367,6 +344,7 @@ public:
367
344
  const auto bal = GetBalance(*m_wallet);
368
345
  WalletBalances result;
369
346
  result.balance = bal.m_mine_trusted;
347
+ result.stake = bal.m_mine_stake;
370
348
  result.unconfirmed_balance = bal.m_mine_untrusted_pending;
371
349
  result.immature_balance = bal.m_mine_immature;
372
350
  result.have_watch_only = haveWatchOnly();
@@ -442,7 +420,7 @@ public:
442
420
  }
443
421
  return result;
444
422
  }
445
- CAmount getRequiredFee(unsigned int tx_bytes) override { return GetRequiredFee(*m_wallet, tx_bytes); }
423
+ /*
446
424
  CAmount getMinimumFee(unsigned int tx_bytes,
447
425
  const CCoinControl& coin_control,
448
426
  int* returned_target,
@@ -456,6 +434,7 @@ public:
456
434
  return result;
457
435
  }
458
436
  unsigned int getConfirmTarget() override { return m_wallet->m_confirm_target; }
437
+ */
459
438
  bool hdEnabled() override { return m_wallet->IsHDEnabled(); }
460
439
  bool canGetAddresses() override { return m_wallet->CanGetAddresses(); }
461
440
  bool hasExternalSigner() override { return m_wallet->IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER); }
@@ -466,7 +445,6 @@ public:
466
445
  return spk_man != nullptr;
467
446
  }
468
447
  OutputType getDefaultAddressType() override { return m_wallet->m_default_address_type; }
469
- CAmount getDefaultMaxTxFee() override { return m_wallet->m_default_max_tx_fee; }
470
448
  void remove() override
471
449
  {
472
450
  RemoveWallet(m_context, m_wallet, false /* load_on_start */);
@@ -505,6 +483,25 @@ public:
505
483
  }
506
484
  CWallet* wallet() override { return m_wallet.get(); }
507
485
 
486
+ void relockWalletAfterDuration(int nDuration) override
487
+ {
488
+ // Keep a weak pointer to the wallet so that it is possible to unload the
489
+ // wallet before the following callback is called. If a valid shared pointer
490
+ // is acquired in the callback then the wallet is still loaded.
491
+ std::weak_ptr<CWallet> weak_wallet = m_wallet;
492
+ m_wallet->chain().rpcRunLater(strprintf("lockwallet(%s)", m_wallet->GetName()), [weak_wallet] {
493
+ if (auto shared_wallet = weak_wallet.lock()) {
494
+ LOCK(shared_wallet->cs_wallet);
495
+ shared_wallet->Lock();
496
+ shared_wallet->nRelockTime = 0;
497
+ }
498
+ }, nDuration);
499
+ }
500
+
501
+ virtual std::shared_ptr<CWallet> getWallet() override {
502
+ return m_wallet;
503
+ }
504
+
508
505
  WalletContext& m_context;
509
506
  std::shared_ptr<CWallet> m_wallet;
510
507
  };
src/wallet/receive.cpp CHANGED
@@ -231,6 +231,36 @@ void CachedTxGetAmounts(const CWallet& wallet, const CWalletTx& wtx,
231
231
  }
232
232
 
233
233
  LOCK(wallet.cs_wallet);
234
+
235
+ // treat coinstake as a single "recieve" entry
236
+ if (wtx.IsCoinStake())
237
+ {
238
+ for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i)
239
+ {
240
+ const CTxOut& txout = wtx.tx->vout[i];
241
+ isminetype fIsMine = wallet.IsMine(txout);
242
+
243
+ // get my vout with positive output
244
+ if (!(fIsMine & filter) || txout.nValue <= 0)
245
+ continue;
246
+
247
+ // get address
248
+ CTxDestination address = CNoDestination();
249
+ ExtractDestination(txout.scriptPubKey, address);
250
+
251
+ // nfee is negative for coinstake generation, because we are gaining money from it
252
+ COutputEntry output = {address, -nFee, (int)i};
253
+ listReceived.push_back(output);
254
+ nFee = 0;
255
+ return;
256
+ }
257
+
258
+ // if we reach here there is probably a mistake
259
+ COutputEntry output = {CNoDestination(), 0, 0};
260
+ listReceived.push_back(output);
261
+ return;
262
+ }
263
+
234
264
  // Sent/received.
235
265
  for (unsigned int i = 0; i < wtx.tx->vout.size(); ++i)
236
266
  {
src/wallet/receive.h CHANGED
@@ -53,6 +53,7 @@ struct Balance {
53
53
  CAmount m_mine_trusted{0}; //!< Trusted, at depth=GetBalance.min_depth or more
54
54
  CAmount m_mine_untrusted_pending{0}; //!< Untrusted, but in mempool (pending)
55
55
  CAmount m_mine_immature{0}; //!< Immature coinbases in the main chain
56
+ CAmount m_mine_stake{0}; //!< Staked, non-spendable until maturity
56
57
  CAmount m_watchonly_trusted{0};
57
58
  CAmount m_watchonly_untrusted_pending{0};
58
59
  CAmount m_watchonly_immature{0};
src/wallet/rpc/addresses.cpp CHANGED
@@ -17,7 +17,7 @@ namespace wallet {
17
17
  RPCHelpMan getnewaddress()
18
18
  {
19
19
  return RPCHelpMan{"getnewaddress",
20
- "\nReturns a new Bitcoin address for receiving payments.\n"
20
+ "\nReturns a new Peercoin address for receiving payments.\n"
21
21
  "If 'label' is specified, it is added to the address book \n"
22
22
  "so payments received with the address will be associated with 'label'.\n",
23
23
  {
@@ -25,7 +25,7 @@ RPCHelpMan getnewaddress()
25
25
  {"address_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -addresstype"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."},
26
26
  },
27
27
  RPCResult{
28
- RPCResult::Type::STR, "address", "The new bitcoin address"
28
+ RPCResult::Type::STR, "address", "The new peercoin address"
29
29
  },
30
30
  RPCExamples{
31
31
  HelpExampleCli("getnewaddress", "")
@@ -72,7 +72,7 @@ RPCHelpMan getnewaddress()
72
72
  RPCHelpMan getrawchangeaddress()
73
73
  {
74
74
  return RPCHelpMan{"getrawchangeaddress",
75
- "\nReturns a new Bitcoin address, for receiving change.\n"
75
+ "\nReturns a new Peercoin address, for receiving change.\n"
76
76
  "This is for use with raw transactions, NOT normal use.\n",
77
77
  {
78
78
  {"address_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The address type to use. Options are \"legacy\", \"p2sh-segwit\", \"bech32\", and \"bech32m\"."},
@@ -122,7 +122,7 @@ RPCHelpMan setlabel()
122
122
  return RPCHelpMan{"setlabel",
123
123
  "\nSets the label associated with the given address.\n",
124
124
  {
125
- {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to be associated with a label."},
125
+ {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The peercoin address to be associated with a label."},
126
126
  {"label", RPCArg::Type::STR, RPCArg::Optional::NO, "The label to assign to the address."},
127
127
  },
128
128
  RPCResult{RPCResult::Type::NONE, "", ""},
@@ -139,7 +139,7 @@ RPCHelpMan setlabel()
139
139
 
140
140
  CTxDestination dest = DecodeDestination(request.params[0].get_str());
141
141
  if (!IsValidDestination(dest)) {
142
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
142
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Peercoin address");
143
143
  }
144
144
 
145
145
  std::string label = LabelFromValue(request.params[1]);
@@ -169,7 +169,7 @@ RPCHelpMan listaddressgroupings()
169
169
  {
170
170
  {RPCResult::Type::ARR_FIXED, "", "",
171
171
  {
172
- {RPCResult::Type::STR, "address", "The bitcoin address"},
172
+ {RPCResult::Type::STR, "address", "The peercoin address"},
173
173
  {RPCResult::Type::STR_AMOUNT, "amount", "The amount in " + CURRENCY_UNIT},
174
174
  {RPCResult::Type::STR, "label", /*optional=*/true, "The label"},
175
175
  }},
@@ -219,15 +219,15 @@ RPCHelpMan addmultisigaddress()
219
219
  {
220
220
  return RPCHelpMan{"addmultisigaddress",
221
221
  "\nAdd an nrequired-to-sign multisignature address to the wallet. Requires a new wallet backup.\n"
222
- "Each key is a Bitcoin address or hex-encoded public key.\n"
222
+ "Each key is a Peercoin address or hex-encoded public key.\n"
223
223
  "This functionality is only intended for use with non-watchonly addresses.\n"
224
224
  "See `importaddress` for watchonly p2sh address support.\n"
225
225
  "If 'label' is specified, assign address to that label.\n",
226
226
  {
227
227
  {"nrequired", RPCArg::Type::NUM, RPCArg::Optional::NO, "The number of required signatures out of the n keys or addresses."},
228
- {"keys", RPCArg::Type::ARR, RPCArg::Optional::NO, "The bitcoin addresses or hex-encoded public keys",
228
+ {"keys", RPCArg::Type::ARR, RPCArg::Optional::NO, "The peercoin addresses or hex-encoded public keys",
229
229
  {
230
- {"key", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "bitcoin address or hex-encoded public key"},
230
+ {"key", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "peercoin address or hex-encoded public key"},
231
231
  },
232
232
  },
233
233
  {"label", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A label to assign the addresses to."},
@@ -496,15 +496,15 @@ static UniValue DescribeWalletAddress(const CWallet& wallet, const CTxDestinatio
496
496
  RPCHelpMan getaddressinfo()
497
497
  {
498
498
  return RPCHelpMan{"getaddressinfo",
499
- "\nReturn information about the given bitcoin address.\n"
499
+ "\nReturn information about the given peercoin address.\n"
500
500
  "Some of the information will only be present if the address is in the active wallet.\n",
501
501
  {
502
- {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address for which to get information."},
502
+ {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The peercoin address for which to get information."},
503
503
  },
504
504
  RPCResult{
505
505
  RPCResult::Type::OBJ, "", "",
506
506
  {
507
- {RPCResult::Type::STR, "address", "The bitcoin address validated."},
507
+ {RPCResult::Type::STR, "address", "The peercoin address validated."},
508
508
  {RPCResult::Type::STR_HEX, "scriptPubKey", "The hex-encoded scriptPubKey generated by the address."},
509
509
  {RPCResult::Type::BOOL, "ismine", "If the address is yours."},
510
510
  {RPCResult::Type::BOOL, "iswatchonly", "If the address is watchonly."},
@@ -768,7 +768,7 @@ RPCHelpMan walletdisplayaddress()
768
768
  "walletdisplayaddress",
769
769
  "Display address on an external signer for verification.",
770
770
  {
771
- {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "bitcoin address to display"},
771
+ {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "peercoin address to display"},
772
772
  },
773
773
  RPCResult{
774
774
  RPCResult::Type::OBJ,"","",
src/wallet/rpc/backup.cpp CHANGED
@@ -148,13 +148,6 @@ RPCHelpMan importprivkey()
148
148
  if (!request.params[2].isNull())
149
149
  fRescan = request.params[2].get_bool();
150
150
 
151
- if (fRescan && pwallet->chain().havePruned()) {
152
- // Exit early and print an error.
153
- // If a block is pruned after this check, we will import the key(s),
154
- // but fail the rescan with a generic error.
155
- throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned");
156
- }
157
-
158
151
  if (fRescan && !reserver.reserve()) {
159
152
  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
160
153
  }
@@ -239,13 +232,6 @@ RPCHelpMan importaddress()
239
232
  if (!request.params[2].isNull())
240
233
  fRescan = request.params[2].get_bool();
241
234
 
242
- if (fRescan && pwallet->chain().havePruned()) {
243
- // Exit early and print an error.
244
- // If a block is pruned after this check, we will import the key(s),
245
- // but fail the rescan with a generic error.
246
- throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned");
247
- }
248
-
249
235
  WalletRescanReserver reserver(*pwallet);
250
236
  if (fRescan && !reserver.reserve()) {
251
237
  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
@@ -284,7 +270,7 @@ RPCHelpMan importaddress()
284
270
 
285
271
  pwallet->ImportScriptPubKeys(strLabel, scripts, false /* have_solving_data */, true /* apply_label */, 1 /* timestamp */);
286
272
  } else {
287
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address or script");
273
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Peercoin address or script");
288
274
  }
289
275
  }
290
276
  if (fRescan)
@@ -301,99 +287,6 @@ RPCHelpMan importaddress()
301
287
  };
302
288
  }
303
289
 
304
- RPCHelpMan importprunedfunds()
305
- {
306
- return RPCHelpMan{"importprunedfunds",
307
- "\nImports funds without rescan. Corresponding address or script must previously be included in wallet. Aimed towards pruned wallets. The end-user is responsible to import additional transactions that subsequently spend the imported outputs or rescan after the point in the blockchain the transaction is included.\n",
308
- {
309
- {"rawtransaction", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "A raw transaction in hex funding an already-existing address in wallet"},
310
- {"txoutproof", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex output from gettxoutproof that contains the transaction"},
311
- },
312
- RPCResult{RPCResult::Type::NONE, "", ""},
313
- RPCExamples{""},
314
- [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
315
- {
316
- std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
317
- if (!pwallet) return NullUniValue;
318
-
319
- CMutableTransaction tx;
320
- if (!DecodeHexTx(tx, request.params[0].get_str())) {
321
- throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed. Make sure the tx has at least one input.");
322
- }
323
- uint256 hashTx = tx.GetHash();
324
-
325
- CDataStream ssMB(ParseHexV(request.params[1], "proof"), SER_NETWORK, PROTOCOL_VERSION);
326
- CMerkleBlock merkleBlock;
327
- ssMB >> merkleBlock;
328
-
329
- //Search partial merkle tree in proof for our transaction and index in valid block
330
- std::vector<uint256> vMatch;
331
- std::vector<unsigned int> vIndex;
332
- if (merkleBlock.txn.ExtractMatches(vMatch, vIndex) != merkleBlock.header.hashMerkleRoot) {
333
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Something wrong with merkleblock");
334
- }
335
-
336
- LOCK(pwallet->cs_wallet);
337
- int height;
338
- if (!pwallet->chain().findAncestorByHash(pwallet->GetLastBlockHash(), merkleBlock.header.GetHash(), FoundBlock().height(height))) {
339
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Block not found in chain");
340
- }
341
-
342
- std::vector<uint256>::const_iterator it;
343
- if ((it = std::find(vMatch.begin(), vMatch.end(), hashTx)) == vMatch.end()) {
344
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Transaction given doesn't exist in proof");
345
- }
346
-
347
- unsigned int txnIndex = vIndex[it - vMatch.begin()];
348
-
349
- CTransactionRef tx_ref = MakeTransactionRef(tx);
350
- if (pwallet->IsMine(*tx_ref)) {
351
- pwallet->AddToWallet(std::move(tx_ref), TxStateConfirmed{merkleBlock.header.GetHash(), height, static_cast<int>(txnIndex)});
352
- return NullUniValue;
353
- }
354
-
355
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "No addresses in wallet correspond to included transaction");
356
- },
357
- };
358
- }
359
-
360
- RPCHelpMan removeprunedfunds()
361
- {
362
- return RPCHelpMan{"removeprunedfunds",
363
- "\nDeletes the specified transaction from the wallet. Meant for use with pruned wallets and as a companion to importprunedfunds. This will affect wallet balances.\n",
364
- {
365
- {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The hex-encoded id of the transaction you are deleting"},
366
- },
367
- RPCResult{RPCResult::Type::NONE, "", ""},
368
- RPCExamples{
369
- HelpExampleCli("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"") +
370
- "\nAs a JSON-RPC call\n"
371
- + HelpExampleRpc("removeprunedfunds", "\"a8d0c0184dde994a09ec054286f1ce581bebf46446a512166eae7628734ea0a5\"")
372
- },
373
- [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
374
- {
375
- std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
376
- if (!pwallet) return NullUniValue;
377
-
378
- LOCK(pwallet->cs_wallet);
379
-
380
- uint256 hash(ParseHashV(request.params[0], "txid"));
381
- std::vector<uint256> vHash;
382
- vHash.push_back(hash);
383
- std::vector<uint256> vHashOut;
384
-
385
- if (pwallet->ZapSelectTx(vHash, vHashOut) != DBErrors::LOAD_OK) {
386
- throw JSONRPCError(RPC_WALLET_ERROR, "Could not properly delete the transaction.");
387
- }
388
-
389
- if(vHashOut.empty()) {
390
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Transaction does not exist in wallet.");
391
- }
392
-
393
- return NullUniValue;
394
- },
395
- };
396
- }
397
290
 
398
291
  RPCHelpMan importpubkey()
399
292
  {
@@ -433,13 +326,6 @@ RPCHelpMan importpubkey()
433
326
  if (!request.params[2].isNull())
434
327
  fRescan = request.params[2].get_bool();
435
328
 
436
- if (fRescan && pwallet->chain().havePruned()) {
437
- // Exit early and print an error.
438
- // If a block is pruned after this check, we will import the key(s),
439
- // but fail the rescan with a generic error.
440
- throw JSONRPCError(RPC_WALLET_ERROR, "Rescan is disabled when blocks are pruned");
441
- }
442
-
443
329
  WalletRescanReserver reserver(*pwallet);
444
330
  if (fRescan && !reserver.reserve()) {
445
331
  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
@@ -505,13 +391,6 @@ RPCHelpMan importwallet()
505
391
 
506
392
  EnsureLegacyScriptPubKeyMan(*pwallet, true);
507
393
 
508
- if (pwallet->chain().havePruned()) {
509
- // Exit early and print an error.
510
- // If a block is pruned after this check, we will import the key(s),
511
- // but fail the rescan with a generic error.
512
- throw JSONRPCError(RPC_WALLET_ERROR, "Importing wallets is disabled when blocks are pruned");
513
- }
514
-
515
394
  WalletRescanReserver reserver(*pwallet);
516
395
  if (!reserver.reserve()) {
517
396
  throw JSONRPCError(RPC_WALLET_ERROR, "Wallet is currently rescanning. Abort existing rescan or wait.");
@@ -644,7 +523,7 @@ RPCHelpMan dumpprivkey()
644
523
  "\nReveals the private key corresponding to 'address'.\n"
645
524
  "Then the importprivkey can be used with this output\n",
646
525
  {
647
- {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address for the private key"},
526
+ {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The peercoin address for the private key"},
648
527
  },
649
528
  RPCResult{
650
529
  RPCResult::Type::STR, "key", "The private key"
@@ -668,7 +547,7 @@ RPCHelpMan dumpprivkey()
668
547
  std::string strAddress = request.params[0].get_str();
669
548
  CTxDestination dest = DecodeDestination(strAddress);
670
549
  if (!IsValidDestination(dest)) {
671
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
550
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Peercoin address");
672
551
  }
673
552
  auto keyid = GetKeyForDestination(spk_man, dest);
674
553
  if (keyid.IsNull()) {
@@ -1420,7 +1299,7 @@ RPCHelpMan importmulti()
1420
1299
  "block from time %d, which is after or within %d seconds of key creation, and "
1421
1300
  "could contain transactions pertaining to the key. As a result, transactions "
1422
1301
  "and coins using this key may not appear in the wallet. This error could be "
1423
- "caused by pruning or data corruption (see bitcoind log for details) and could "
1302
+ "caused by pruning or data corruption (see peercoind log for details) and could "
1424
1303
  "be dealt with by downloading and rescanning the relevant blocks (see -reindex "
1425
1304
  "option and rescanblockchain RPC).",
1426
1305
  GetImportTimestamp(request, now), scannedTime - TIMESTAMP_WINDOW - 1, TIMESTAMP_WINDOW)));
src/wallet/rpc/coins.cpp CHANGED
@@ -28,7 +28,7 @@ static CAmount GetReceived(const CWallet& wallet, const UniValue& params, bool b
28
28
  // Get the address
29
29
  CTxDestination dest = DecodeDestination(params[0].get_str());
30
30
  if (!IsValidDestination(dest)) {
31
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Bitcoin address");
31
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Invalid Peercoin address");
32
32
  }
33
33
  CScript script_pub_key = GetScriptForDestination(dest);
34
34
  if (!wallet.IsMine(script_pub_key)) {
@@ -82,7 +82,7 @@ RPCHelpMan getreceivedbyaddress()
82
82
  return RPCHelpMan{"getreceivedbyaddress",
83
83
  "\nReturns the total amount received by the given address in transactions with at least minconf confirmations.\n",
84
84
  {
85
- {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address for transactions."},
85
+ {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The peercoin address for transactions."},
86
86
  {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "Only include transactions confirmed at least this many times."},
87
87
  {"include_immature_coinbase", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include immature coinbase transactions."},
88
88
  },
@@ -243,7 +243,7 @@ RPCHelpMan lockunspent()
243
243
  "\nUpdates list of temporarily unspendable outputs.\n"
244
244
  "Temporarily lock (unlock=false) or unlock (unlock=true) specified transaction outputs.\n"
245
245
  "If no transaction outputs are specified when unlocking then all current locked transaction outputs are unlocked.\n"
246
- "A locked transaction output will not be chosen by automatic coin selection, when spending bitcoins.\n"
246
+ "A locked transaction output will not be chosen by automatic coin selection, when spending peercoins.\n"
247
247
  "Manually selected coins are automatically unlocked.\n"
248
248
  "Locks are stored in memory only, unless persistent=true, in which case they will be written to the\n"
249
249
  "wallet database and loaded on node start. Unwritten (persistent=false) locks are always cleared\n"
@@ -507,9 +507,9 @@ RPCHelpMan listunspent()
507
507
  {
508
508
  {"minconf", RPCArg::Type::NUM, RPCArg::Default{1}, "The minimum confirmations to filter"},
509
509
  {"maxconf", RPCArg::Type::NUM, RPCArg::Default{9999999}, "The maximum confirmations to filter"},
510
- {"addresses", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The bitcoin addresses to filter",
510
+ {"addresses", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The peercoin addresses to filter",
511
511
  {
512
- {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "bitcoin address"},
512
+ {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "peercoin address"},
513
513
  },
514
514
  },
515
515
  {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{true}, "Include outputs that are not safe to spend\n"
@@ -530,7 +530,7 @@ RPCHelpMan listunspent()
530
530
  {
531
531
  {RPCResult::Type::STR_HEX, "txid", "the transaction id"},
532
532
  {RPCResult::Type::NUM, "vout", "the vout value"},
533
- {RPCResult::Type::STR, "address", /*optional=*/true, "the bitcoin address"},
533
+ {RPCResult::Type::STR, "address", /*optional=*/true, "the peercoin address"},
534
534
  {RPCResult::Type::STR, "label", /*optional=*/true, "The associated label, or \"\" for the default label"},
535
535
  {RPCResult::Type::STR, "scriptPubKey", "the script key"},
536
536
  {RPCResult::Type::STR_AMOUNT, "amount", "the transaction output amount in " + CURRENCY_UNIT},
@@ -582,7 +582,7 @@ RPCHelpMan listunspent()
582
582
  const UniValue& input = inputs[idx];
583
583
  CTxDestination dest = DecodeDestination(input.get_str());
584
584
  if (!IsValidDestination(dest)) {
585
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + input.get_str());
585
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Peercoin address: ") + input.get_str());
586
586
  }
587
587
  if (!destinations.insert(dest).second) {
588
588
  throw JSONRPCError(RPC_INVALID_PARAMETER, std::string("Invalid parameter, duplicated address: ") + input.get_str());
src/wallet/rpc/encrypt.cpp CHANGED
@@ -19,15 +19,19 @@ RPCHelpMan walletpassphrase()
19
19
  {
20
20
  {"passphrase", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet passphrase"},
21
21
  {"timeout", RPCArg::Type::NUM, RPCArg::Optional::NO, "The time to keep the decryption key in seconds; capped at 100000000 (~3 years)."},
22
+ {"mintonly", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED, "Unlock for minting only"},
22
23
  },
23
- RPCResult{RPCResult::Type::NONE, "", ""},
24
+ RPCResult{RPCResult::Type::OBJ, "", "",
25
+ {
26
+ {RPCResult::Type::BOOL, "unlocked_minting_only", "Whether wallet is unlocked for minting only."}
27
+ }},
24
28
  RPCExamples{
25
29
  "\nUnlock the wallet for 60 seconds\n"
26
- + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60") +
30
+ + HelpExampleCli("walletpassphrase", "\"my pass phrase\" 60, false") +
27
31
  "\nLock the wallet again (before 60 seconds)\n"
28
32
  + HelpExampleCli("walletlock", "") +
29
33
  "\nAs a JSON-RPC call\n"
30
- + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60")
34
+ + HelpExampleRpc("walletpassphrase", "\"my pass phrase\", 60, false")
31
35
  },
32
36
  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
33
37
  {
@@ -98,7 +102,16 @@ RPCHelpMan walletpassphrase()
98
102
  }
99
103
  }, nSleepTime);
100
104
 
101
- return NullUniValue;
105
+ // peercoin: if user OS account compromised prevent trivial sendmoney commands
106
+ if (request.params.size() > 2)
107
+ fWalletUnlockMintOnly = request.params[2].get_bool();
108
+ else
109
+ fWalletUnlockMintOnly = false;
110
+
111
+ UniValue ret(UniValue::VOBJ);
112
+ ret.pushKV("unlocked_minting_only", fWalletUnlockMintOnly);
113
+
114
+ return ret;
102
115
  },
103
116
  };
104
117
  }
src/wallet/rpc/spend.cpp CHANGED
@@ -12,7 +12,6 @@
12
12
  #include <util/translation.h>
13
13
  #include <util/vector.h>
14
14
  #include <wallet/coincontrol.h>
15
- #include <wallet/feebumper.h>
16
15
  #include <wallet/rpc/util.h>
17
16
  #include <wallet/spend.h>
18
17
  #include <wallet/wallet.h>
@@ -27,7 +26,7 @@ static void ParseRecipients(const UniValue& address_amounts, const UniValue& sub
27
26
  for (const std::string& address: address_amounts.getKeys()) {
28
27
  CTxDestination dest = DecodeDestination(address);
29
28
  if (!IsValidDestination(dest)) {
30
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Bitcoin address: ") + address);
29
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, std::string("Invalid Peercoin address: ") + address);
31
30
  }
32
31
 
33
32
  if (destinations.count(dest)) {
@@ -69,7 +68,7 @@ UniValue SendMoney(CWallet& wallet, const CCoinControl &coin_control, std::vecto
69
68
  int nChangePosRet = -1;
70
69
  bilingual_str error;
71
70
  CTransactionRef tx;
72
- FeeCalculation fee_calc_out;
71
+ CAmount fee_calc_out;
73
72
  const bool fCreated = CreateTransaction(wallet, recipients, tx, nFeeRequired, nChangePosRet, error, coin_control, fee_calc_out, true);
74
73
  if (!fCreated) {
75
74
  throw JSONRPCError(RPC_WALLET_INSUFFICIENT_FUNDS, error.original);
@@ -78,57 +77,18 @@ UniValue SendMoney(CWallet& wallet, const CCoinControl &coin_control, std::vecto
78
77
  if (verbose) {
79
78
  UniValue entry(UniValue::VOBJ);
80
79
  entry.pushKV("txid", tx->GetHash().GetHex());
81
- entry.pushKV("fee_reason", StringForFeeReason(fee_calc_out.reason));
82
80
  return entry;
83
81
  }
84
82
  return tx->GetHash().GetHex();
85
83
  }
86
84
 
87
-
88
- /**
89
- * Update coin control with fee estimation based on the given parameters
90
- *
91
- * @param[in] wallet Wallet reference
92
- * @param[in,out] cc Coin control to be updated
93
- * @param[in] conf_target UniValue integer; confirmation target in blocks, values between 1 and 1008 are valid per policy/fees.h;
94
- * @param[in] estimate_mode UniValue string; fee estimation mode, valid values are "unset", "economical" or "conservative";
95
- * @param[in] fee_rate UniValue real; fee rate in sat/vB;
96
- * if present, both conf_target and estimate_mode must either be null, or "unset"
97
- * @param[in] override_min_fee bool; whether to set fOverrideFeeRate to true to disable minimum fee rate checks and instead
98
- * verify only that fee_rate is greater than 0
99
- * @throws a JSONRPCError if conf_target, estimate_mode, or fee_rate contain invalid values or are in conflict
100
- */
101
- static void SetFeeEstimateMode(const CWallet& wallet, CCoinControl& cc, const UniValue& conf_target, const UniValue& estimate_mode, const UniValue& fee_rate, bool override_min_fee)
102
- {
103
- if (!fee_rate.isNull()) {
104
- if (!conf_target.isNull()) {
105
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both conf_target and fee_rate. Please provide either a confirmation target in blocks for automatic fee estimation, or an explicit fee rate.");
106
- }
107
- if (!estimate_mode.isNull() && estimate_mode.get_str() != "unset") {
108
- throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and fee_rate");
109
- }
110
- // Fee rates in sat/vB cannot represent more than 3 significant digits.
111
- cc.m_feerate = CFeeRate{AmountFromValue(fee_rate, /* decimals */ 3)};
112
- if (override_min_fee) cc.fOverrideFeeRate = true;
113
- // Default RBF to true for explicit fee_rate, if unset.
114
- if (!cc.m_signal_bip125_rbf) cc.m_signal_bip125_rbf = true;
115
- return;
116
- }
117
- if (!estimate_mode.isNull() && !FeeModeFromString(estimate_mode.get_str(), cc.m_fee_mode)) {
118
- throw JSONRPCError(RPC_INVALID_PARAMETER, InvalidEstimateModeErrorMessage());
119
- }
120
- if (!conf_target.isNull()) {
121
- cc.m_confirm_target = ParseConfirmTarget(conf_target, wallet.chain().estimateMaxBlocks());
122
- }
123
- }
124
-
125
85
  RPCHelpMan sendtoaddress()
126
86
  {
127
87
  return RPCHelpMan{"sendtoaddress",
128
88
  "\nSend an amount to a given address." +
129
89
  HELP_REQUIRING_PASSPHRASE,
130
90
  {
131
- {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The bitcoin address to send to."},
91
+ {"address", RPCArg::Type::STR, RPCArg::Optional::NO, "The peercoin address to send to."},
132
92
  {"amount", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The amount in " + CURRENCY_UNIT + " to send. eg 0.1"},
133
93
  {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment used to store what the transaction is for.\n"
134
94
  "This is not part of the transaction, just kept in your wallet."},
@@ -136,11 +96,8 @@ RPCHelpMan sendtoaddress()
136
96
  "to which you're sending the transaction. This is not part of the \n"
137
97
  "transaction, just kept in your wallet."},
138
98
  {"subtractfeefromamount", RPCArg::Type::BOOL, RPCArg::Default{false}, "The fee will be deducted from the amount being sent.\n"
139
- "The recipient will receive less bitcoins than you enter in the amount field."},
140
- {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
99
+ "The recipient will receive less peercoins than you enter in the amount field."},
141
100
  {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
142
- {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
143
- " \"" + FeeModes("\"\n\"") + "\""},
144
101
  {"avoid_reuse", RPCArg::Type::BOOL, RPCArg::Default{true}, "(only available if avoid_reuse wallet flag is set) Avoid spending from dirty addresses; addresses are considered\n"
145
102
  "dirty if they have previously been used in a transaction. If true, this also activates avoidpartialspends, grouping outputs by their addresses."},
146
103
  {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
@@ -163,13 +120,10 @@ RPCHelpMan sendtoaddress()
163
120
  + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1") +
164
121
  "\nSend 0.1 BTC with a confirmation target of 6 blocks in economical fee estimate mode using positional arguments\n"
165
122
  + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"donation\" \"sean's outpost\" false true 6 economical") +
166
- "\nSend 0.1 BTC with a fee rate of 1.1 " + CURRENCY_ATOM + "/vB, subtract fee from amount, BIP125-replaceable, using positional arguments\n"
167
- + HelpExampleCli("sendtoaddress", "\"" + EXAMPLE_ADDRESS[0] + "\" 0.1 \"drinks\" \"room77\" true true null \"unset\" null 1.1") +
168
123
  "\nSend 0.2 BTC with a confirmation target of 6 blocks in economical fee estimate mode using named arguments\n"
169
124
  + HelpExampleCli("-named sendtoaddress", "address=\"" + EXAMPLE_ADDRESS[0] + "\" amount=0.2 conf_target=6 estimate_mode=\"economical\"") +
170
125
  "\nSend 0.5 BTC with a fee rate of 25 " + CURRENCY_ATOM + "/vB using named arguments\n"
171
126
  + HelpExampleCli("-named sendtoaddress", "address=\"" + EXAMPLE_ADDRESS[0] + "\" amount=0.5 fee_rate=25")
172
- + HelpExampleCli("-named sendtoaddress", "address=\"" + EXAMPLE_ADDRESS[0] + "\" amount=0.5 fee_rate=25 subtractfeefromamount=false replaceable=true avoid_reuse=true comment=\"2 pizzas\" comment_to=\"jeremy\" verbose=true")
173
127
  },
174
128
  [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
175
129
  {
@@ -195,16 +149,11 @@ RPCHelpMan sendtoaddress()
195
149
  }
196
150
 
197
151
  CCoinControl coin_control;
198
- if (!request.params[5].isNull()) {
199
- coin_control.m_signal_bip125_rbf = request.params[5].get_bool();
200
- }
201
152
 
202
153
  coin_control.m_avoid_address_reuse = GetAvoidReuseFlag(*pwallet, request.params[8]);
203
154
  // We also enable partial spend avoidance if reuse avoidance is set.
204
155
  coin_control.m_avoid_partial_spends |= coin_control.m_avoid_address_reuse;
205
156
 
206
- SetFeeEstimateMode(*pwallet, coin_control, /* conf_target */ request.params[6], /* estimate_mode */ request.params[7], /* fee_rate */ request.params[9], /* override_min_fee */ false);
207
-
208
157
  EnsureWalletIsUnlocked(*pwallet);
209
158
 
210
159
  UniValue address_amounts(UniValue::VOBJ);
@@ -233,23 +182,20 @@ RPCHelpMan sendmany()
233
182
  {"dummy", RPCArg::Type::STR, RPCArg::Optional::NO, "Must be set to \"\" for backwards compatibility.", "\"\""},
234
183
  {"amounts", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::NO, "The addresses and amounts",
235
184
  {
236
- {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The bitcoin address is the key, the numeric amount (can be string) in " + CURRENCY_UNIT + " is the value"},
185
+ {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "The peercoin address is the key, the numeric amount (can be string) in " + CURRENCY_UNIT + " is the value"},
237
186
  },
238
187
  },
239
188
  {"minconf", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "Ignored dummy value"},
240
189
  {"comment", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "A comment"},
241
190
  {"subtractfeefrom", RPCArg::Type::ARR, RPCArg::Optional::OMITTED_NAMED_ARG, "The addresses.\n"
242
191
  "The fee will be equally deducted from the amount of each selected address.\n"
243
- "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
192
+ "Those recipients will receive less peercoins than you enter in their corresponding amount field.\n"
244
193
  "If no addresses are specified here, the sender pays the fee.",
245
194
  {
246
195
  {"address", RPCArg::Type::STR, RPCArg::Optional::OMITTED, "Subtract fee from this address"},
247
196
  },
248
197
  },
249
- {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Allow this transaction to be replaced by a transaction with higher fees via BIP 125"},
250
198
  {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
251
- {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
252
- " \"" + FeeModes("\"\n\"") + "\""},
253
199
  {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
254
200
  {"verbose", RPCArg::Type::BOOL, RPCArg::Default{false}, "If true, return extra infomration about the transaction."},
255
201
  },
@@ -302,11 +248,6 @@ RPCHelpMan sendmany()
302
248
  subtractFeeFromAmount = request.params[4].get_array();
303
249
 
304
250
  CCoinControl coin_control;
305
- if (!request.params[5].isNull()) {
306
- coin_control.m_signal_bip125_rbf = request.params[5].get_bool();
307
- }
308
-
309
- SetFeeEstimateMode(*pwallet, coin_control, /* conf_target */ request.params[6], /* estimate_mode */ request.params[7], /* fee_rate */ request.params[8], /* override_min_fee */ false);
310
251
 
311
252
  std::vector<CRecipient> recipients;
312
253
  ParseRecipients(sendTo, subtractFeeFromAmount, recipients);
@@ -339,20 +280,6 @@ RPCHelpMan settxfee()
339
280
 
340
281
  LOCK(pwallet->cs_wallet);
341
282
 
342
- CAmount nAmount = AmountFromValue(request.params[0]);
343
- CFeeRate tx_fee_rate(nAmount, 1000);
344
- CFeeRate max_tx_fee_rate(pwallet->m_default_max_tx_fee, 1000);
345
- if (tx_fee_rate == CFeeRate(0)) {
346
- // automatic selection
347
- } else if (tx_fee_rate < pwallet->chain().relayMinFee()) {
348
- throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than min relay tx fee (%s)", pwallet->chain().relayMinFee().ToString()));
349
- } else if (tx_fee_rate < pwallet->m_min_fee) {
350
- throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be less than wallet min fee (%s)", pwallet->m_min_fee.ToString()));
351
- } else if (tx_fee_rate > max_tx_fee_rate) {
352
- throw JSONRPCError(RPC_INVALID_PARAMETER, strprintf("txfee cannot be more than wallet max tx fee (%s)", max_tx_fee_rate.ToString()));
353
- }
354
-
355
- pwallet->m_pay_tx_fee = tx_fee_rate;
356
283
  return true;
357
284
  },
358
285
  };
@@ -364,10 +291,6 @@ static std::vector<RPCArg> FundTxDoc()
364
291
  {
365
292
  return {
366
293
  {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
367
- {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
368
- " \"" + FeeModes("\"\n\"") + "\""},
369
- {"replaceable", RPCArg::Type::BOOL, RPCArg::DefaultHint{"wallet default"}, "Marks this transaction as BIP125-replaceable.\n"
370
- "Allows this transaction to be replaced by a transaction with higher fees"},
371
294
  {"solving_data", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "Keys and scripts needed for producing a final transaction with a dummy signature.\n"
372
295
  "Used for fee estimation during coin selection.",
373
296
  {
@@ -427,7 +350,6 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out,
427
350
  {"solving_data", UniValueType(UniValue::VOBJ)},
428
351
  {"subtractFeeFromOutputs", UniValueType(UniValue::VARR)},
429
352
  {"subtract_fee_from_outputs", UniValueType(UniValue::VARR)},
430
- {"replaceable", UniValueType(UniValue::VBOOL)},
431
353
  {"conf_target", UniValueType(UniValue::VNUM)},
432
354
  {"estimate_mode", UniValueType(UniValue::VSTR)},
433
355
  {"input_weights", UniValueType(UniValue::VARR)},
@@ -443,7 +365,7 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out,
443
365
  CTxDestination dest = DecodeDestination(change_address_str);
444
366
 
445
367
  if (!IsValidDestination(dest)) {
446
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Change address must be a valid bitcoin address");
368
+ throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, "Change address must be a valid peercoin address");
447
369
  }
448
370
 
449
371
  coinControl.destChange = dest;
@@ -485,17 +407,11 @@ void FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& fee_out,
485
407
  if (options.exists("estimate_mode")) {
486
408
  throw JSONRPCError(RPC_INVALID_PARAMETER, "Cannot specify both estimate_mode and feeRate");
487
409
  }
488
- coinControl.m_feerate = CFeeRate(AmountFromValue(options["feeRate"]));
489
- coinControl.fOverrideFeeRate = true;
490
410
  }
491
411
 
492
412
  if (options.exists("subtractFeeFromOutputs") || options.exists("subtract_fee_from_outputs") )
493
413
  subtractFeeFromOutputs = (options.exists("subtract_fee_from_outputs") ? options["subtract_fee_from_outputs"] : options["subtractFeeFromOutputs"]).get_array();
494
414
 
495
- if (options.exists("replaceable")) {
496
- coinControl.m_signal_bip125_rbf = options["replaceable"].get_bool();
497
- }
498
- SetFeeEstimateMode(wallet, coinControl, options["conf_target"], options["estimate_mode"], options["fee_rate"], override_min_fee);
499
415
  }
500
416
  } else {
501
417
  // if options is null and not a bool
@@ -659,7 +575,7 @@ RPCHelpMan fundrawtransaction()
659
575
  {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
660
576
  "Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"
661
577
  "If that happens, you will need to fund the transaction with different inputs and republish it."},
662
- {"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"pool address"}, "The bitcoin address to receive the change"},
578
+ {"changeAddress", RPCArg::Type::STR, RPCArg::DefaultHint{"pool address"}, "The peercoin address to receive the change"},
663
579
  {"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
664
580
  {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
665
581
  {"includeWatching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only.\n"
@@ -670,7 +586,7 @@ RPCHelpMan fundrawtransaction()
670
586
  {"feeRate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."},
671
587
  {"subtractFeeFromOutputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The integers.\n"
672
588
  "The fee will be equally deducted from the amount of each specified output.\n"
673
- "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
589
+ "Those recipients will receive less peercoins than you enter in their corresponding amount field.\n"
674
590
  "If no outputs are specified here, the sender pays the fee.",
675
591
  {
676
592
  {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
@@ -845,183 +761,6 @@ RPCHelpMan signrawtransactionwithwallet()
845
761
  };
846
762
  }
847
763
 
848
- static RPCHelpMan bumpfee_helper(std::string method_name)
849
- {
850
- const bool want_psbt = method_name == "psbtbumpfee";
851
- const std::string incremental_fee{CFeeRate(DEFAULT_INCREMENTAL_RELAY_FEE).ToString(FeeEstimateMode::SAT_VB)};
852
-
853
- return RPCHelpMan{method_name,
854
- "\nBumps the fee of an opt-in-RBF transaction T, replacing it with a new transaction B.\n"
855
- + std::string(want_psbt ? "Returns a PSBT instead of creating and signing a new transaction.\n" : "") +
856
- "An opt-in RBF transaction with the given txid must be in the wallet.\n"
857
- "The command will pay the additional fee by reducing change outputs or adding inputs when necessary.\n"
858
- "It may add a new change output if one does not already exist.\n"
859
- "All inputs in the original transaction will be included in the replacement transaction.\n"
860
- "The command will fail if the wallet or mempool contains a transaction that spends one of T's outputs.\n"
861
- "By default, the new fee will be calculated automatically using the estimatesmartfee RPC.\n"
862
- "The user can specify a confirmation target for estimatesmartfee.\n"
863
- "Alternatively, the user can specify a fee rate in " + CURRENCY_ATOM + "/vB for the new transaction.\n"
864
- "At a minimum, the new fee rate must be high enough to pay an additional new relay fee (incrementalfee\n"
865
- "returned by getnetworkinfo) to enter the node's mempool.\n"
866
- "* WARNING: before version 0.21, fee_rate was in " + CURRENCY_UNIT + "/kvB. As of 0.21, fee_rate is in " + CURRENCY_ATOM + "/vB. *\n",
867
- {
868
- {"txid", RPCArg::Type::STR_HEX, RPCArg::Optional::NO, "The txid to be bumped"},
869
- {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
870
- {
871
- {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks\n"},
872
- {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"},
873
- "\nSpecify a fee rate in " + CURRENCY_ATOM + "/vB instead of relying on the built-in fee estimator.\n"
874
- "Must be at least " + incremental_fee + " higher than the current transaction fee rate.\n"
875
- "WARNING: before version 0.21, fee_rate was in " + CURRENCY_UNIT + "/kvB. As of 0.21, fee_rate is in " + CURRENCY_ATOM + "/vB.\n"},
876
- {"replaceable", RPCArg::Type::BOOL, RPCArg::Default{true}, "Whether the new transaction should still be\n"
877
- "marked bip-125 replaceable. If true, the sequence numbers in the transaction will\n"
878
- "be left unchanged from the original. If false, any input sequence numbers in the\n"
879
- "original transaction that were less than 0xfffffffe will be increased to 0xfffffffe\n"
880
- "so the new transaction will not be explicitly bip-125 replaceable (though it may\n"
881
- "still be replaceable in practice, for example if it has unconfirmed ancestors which\n"
882
- "are replaceable).\n"},
883
- {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, "The fee estimate mode, must be one of (case insensitive):\n"
884
- "\"" + FeeModes("\"\n\"") + "\""},
885
- },
886
- "options"},
887
- },
888
- RPCResult{
889
- RPCResult::Type::OBJ, "", "", Cat(
890
- want_psbt ?
891
- std::vector<RPCResult>{{RPCResult::Type::STR, "psbt", "The base64-encoded unsigned PSBT of the new transaction."}} :
892
- std::vector<RPCResult>{{RPCResult::Type::STR_HEX, "txid", "The id of the new transaction."}},
893
- {
894
- {RPCResult::Type::STR_AMOUNT, "origfee", "The fee of the replaced transaction."},
895
- {RPCResult::Type::STR_AMOUNT, "fee", "The fee of the new transaction."},
896
- {RPCResult::Type::ARR, "errors", "Errors encountered during processing (may be empty).",
897
- {
898
- {RPCResult::Type::STR, "", ""},
899
- }},
900
- })
901
- },
902
- RPCExamples{
903
- "\nBump the fee, get the new transaction\'s " + std::string(want_psbt ? "psbt" : "txid") + "\n" +
904
- HelpExampleCli(method_name, "<txid>")
905
- },
906
- [want_psbt](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
907
- {
908
- std::shared_ptr<CWallet> const pwallet = GetWalletForJSONRPCRequest(request);
909
- if (!pwallet) return NullUniValue;
910
-
911
- if (pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS) && !want_psbt) {
912
- throw JSONRPCError(RPC_WALLET_ERROR, "bumpfee is not available with wallets that have private keys disabled. Use psbtbumpfee instead.");
913
- }
914
-
915
- RPCTypeCheck(request.params, {UniValue::VSTR, UniValue::VOBJ});
916
- uint256 hash(ParseHashV(request.params[0], "txid"));
917
-
918
- CCoinControl coin_control;
919
- coin_control.fAllowWatchOnly = pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS);
920
- // optional parameters
921
- coin_control.m_signal_bip125_rbf = true;
922
-
923
- if (!request.params[1].isNull()) {
924
- UniValue options = request.params[1];
925
- RPCTypeCheckObj(options,
926
- {
927
- {"confTarget", UniValueType(UniValue::VNUM)},
928
- {"conf_target", UniValueType(UniValue::VNUM)},
929
- {"fee_rate", UniValueType()}, // will be checked by AmountFromValue() in SetFeeEstimateMode()
930
- {"replaceable", UniValueType(UniValue::VBOOL)},
931
- {"estimate_mode", UniValueType(UniValue::VSTR)},
932
- },
933
- true, true);
934
-
935
- if (options.exists("confTarget") && options.exists("conf_target")) {
936
- throw JSONRPCError(RPC_INVALID_PARAMETER, "confTarget and conf_target options should not both be set. Use conf_target (confTarget is deprecated).");
937
- }
938
-
939
- auto conf_target = options.exists("confTarget") ? options["confTarget"] : options["conf_target"];
940
-
941
- if (options.exists("replaceable")) {
942
- coin_control.m_signal_bip125_rbf = options["replaceable"].get_bool();
943
- }
944
- SetFeeEstimateMode(*pwallet, coin_control, conf_target, options["estimate_mode"], options["fee_rate"], /* override_min_fee */ false);
945
- }
946
-
947
- // Make sure the results are valid at least up to the most recent block
948
- // the user could have gotten from another RPC command prior to now
949
- pwallet->BlockUntilSyncedToCurrentChain();
950
-
951
- LOCK(pwallet->cs_wallet);
952
-
953
- EnsureWalletIsUnlocked(*pwallet);
954
-
955
-
956
- std::vector<bilingual_str> errors;
957
- CAmount old_fee;
958
- CAmount new_fee;
959
- CMutableTransaction mtx;
960
- feebumper::Result res;
961
- // Targeting feerate bump.
962
- res = feebumper::CreateRateBumpTransaction(*pwallet, hash, coin_control, errors, old_fee, new_fee, mtx);
963
- if (res != feebumper::Result::OK) {
964
- switch(res) {
965
- case feebumper::Result::INVALID_ADDRESS_OR_KEY:
966
- throw JSONRPCError(RPC_INVALID_ADDRESS_OR_KEY, errors[0].original);
967
- break;
968
- case feebumper::Result::INVALID_REQUEST:
969
- throw JSONRPCError(RPC_INVALID_REQUEST, errors[0].original);
970
- break;
971
- case feebumper::Result::INVALID_PARAMETER:
972
- throw JSONRPCError(RPC_INVALID_PARAMETER, errors[0].original);
973
- break;
974
- case feebumper::Result::WALLET_ERROR:
975
- throw JSONRPCError(RPC_WALLET_ERROR, errors[0].original);
976
- break;
977
- default:
978
- throw JSONRPCError(RPC_MISC_ERROR, errors[0].original);
979
- break;
980
- }
981
- }
982
-
983
- UniValue result(UniValue::VOBJ);
984
-
985
- // For bumpfee, return the new transaction id.
986
- // For psbtbumpfee, return the base64-encoded unsigned PSBT of the new transaction.
987
- if (!want_psbt) {
988
- if (!feebumper::SignTransaction(*pwallet, mtx)) {
989
- throw JSONRPCError(RPC_WALLET_ERROR, "Can't sign transaction.");
990
- }
991
-
992
- uint256 txid;
993
- if (feebumper::CommitTransaction(*pwallet, hash, std::move(mtx), errors, txid) != feebumper::Result::OK) {
994
- throw JSONRPCError(RPC_WALLET_ERROR, errors[0].original);
995
- }
996
-
997
- result.pushKV("txid", txid.GetHex());
998
- } else {
999
- PartiallySignedTransaction psbtx(mtx);
1000
- bool complete = false;
1001
- const TransactionError err = pwallet->FillPSBT(psbtx, complete, SIGHASH_DEFAULT, false /* sign */, true /* bip32derivs */);
1002
- CHECK_NONFATAL(err == TransactionError::OK);
1003
- CHECK_NONFATAL(!complete);
1004
- CDataStream ssTx(SER_NETWORK, PROTOCOL_VERSION);
1005
- ssTx << psbtx;
1006
- result.pushKV("psbt", EncodeBase64(ssTx.str()));
1007
- }
1008
-
1009
- result.pushKV("origfee", ValueFromAmount(old_fee));
1010
- result.pushKV("fee", ValueFromAmount(new_fee));
1011
- UniValue result_errors(UniValue::VARR);
1012
- for (const bilingual_str& error : errors) {
1013
- result_errors.push_back(error.original);
1014
- }
1015
- result.pushKV("errors", result_errors);
1016
-
1017
- return result;
1018
- },
1019
- };
1020
- }
1021
-
1022
- RPCHelpMan bumpfee() { return bumpfee_helper("bumpfee"); }
1023
- RPCHelpMan psbtbumpfee() { return bumpfee_helper("psbtbumpfee"); }
1024
-
1025
764
  RPCHelpMan send()
1026
765
  {
1027
766
  return RPCHelpMan{"send",
@@ -1034,7 +773,7 @@ RPCHelpMan send()
1034
773
  {
1035
774
  {"", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED, "",
1036
775
  {
1037
- {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + ""},
776
+ {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the peercoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + ""},
1038
777
  },
1039
778
  },
1040
779
  {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
@@ -1045,8 +784,6 @@ RPCHelpMan send()
1045
784
  },
1046
785
  },
1047
786
  {"conf_target", RPCArg::Type::NUM, RPCArg::DefaultHint{"wallet -txconfirmtarget"}, "Confirmation target in blocks"},
1048
- {"estimate_mode", RPCArg::Type::STR, RPCArg::Default{"unset"}, std::string() + "The fee estimate mode, must be one of (case insensitive):\n"
1049
- " \"" + FeeModes("\"\n\"") + "\""},
1050
787
  {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
1051
788
  {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
1052
789
  Cat<std::vector<RPCArg>>(
@@ -1056,7 +793,7 @@ RPCHelpMan send()
1056
793
  "Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"
1057
794
  "If that happens, you will need to fund the transaction with different inputs and republish it."},
1058
795
  {"add_to_wallet", RPCArg::Type::BOOL, RPCArg::Default{true}, "When false, returns a serialized transaction which will not be added to the wallet or broadcast"},
1059
- {"change_address", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"pool address"}, "The bitcoin address to receive the change"},
796
+ {"change_address", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"pool address"}, "The peercoin address to receive the change"},
1060
797
  {"change_position", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
1061
798
  {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if change_address is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
1062
799
  {"fee_rate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_ATOM + "/vB."},
@@ -1080,7 +817,7 @@ RPCHelpMan send()
1080
817
  {"psbt", RPCArg::Type::BOOL, RPCArg::DefaultHint{"automatic"}, "Always return a PSBT, implies add_to_wallet=false."},
1081
818
  {"subtract_fee_from_outputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "Outputs to subtract the fee from, specified as integer indices.\n"
1082
819
  "The fee will be equally deducted from the amount of each specified output.\n"
1083
- "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
820
+ "Those recipients will receive less peercoins than you enter in their corresponding amount field.\n"
1084
821
  "If no outputs are specified here, the sender pays the fee.",
1085
822
  {
1086
823
  {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
@@ -1167,11 +904,7 @@ RPCHelpMan send()
1167
904
 
1168
905
  CAmount fee;
1169
906
  int change_position;
1170
- bool rbf = pwallet->m_signal_rbf;
1171
- if (options.exists("replaceable")) {
1172
- rbf = options["replaceable"].get_bool();
1173
- }
1174
- CMutableTransaction rawTx = ConstructTransaction(options["inputs"], request.params[0], options["locktime"], rbf);
907
+ CMutableTransaction rawTx = ConstructTransaction(options["inputs"], request.params[0], options["locktime"], false);
1175
908
  CCoinControl coin_control;
1176
909
  // Automatically select coins, unless at least one is manually selected. Can
1177
910
  // be overridden by options.add_inputs.
@@ -1333,7 +1066,7 @@ RPCHelpMan walletcreatefundedpsbt()
1333
1066
  {
1334
1067
  {"", RPCArg::Type::OBJ_USER_KEYS, RPCArg::Optional::OMITTED, "",
1335
1068
  {
1336
- {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the bitcoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + ""},
1069
+ {"address", RPCArg::Type::AMOUNT, RPCArg::Optional::NO, "A key-value pair. The key (string) is the peercoin address, the value (float or string) is the amount in " + CURRENCY_UNIT + ""},
1337
1070
  },
1338
1071
  },
1339
1072
  {"", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED, "",
@@ -1344,6 +1077,7 @@ RPCHelpMan walletcreatefundedpsbt()
1344
1077
  },
1345
1078
  },
1346
1079
  {"locktime", RPCArg::Type::NUM, RPCArg::Default{0}, "Raw locktime. Non-0 value also locktime-activates inputs"},
1080
+ {"timestamp", RPCArg::Type::NUM, RPCArg::Default{0}, "Transaction timestamp"},
1347
1081
  {"options", RPCArg::Type::OBJ, RPCArg::Optional::OMITTED_NAMED_ARG, "",
1348
1082
  Cat<std::vector<RPCArg>>(
1349
1083
  {
@@ -1351,7 +1085,7 @@ RPCHelpMan walletcreatefundedpsbt()
1351
1085
  {"include_unsafe", RPCArg::Type::BOOL, RPCArg::Default{false}, "Include inputs that are not safe to spend (unconfirmed transactions from outside keys and unconfirmed replacement transactions).\n"
1352
1086
  "Warning: the resulting transaction may become invalid if one of the unsafe inputs disappears.\n"
1353
1087
  "If that happens, you will need to fund the transaction with different inputs and republish it."},
1354
- {"changeAddress", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"pool address"}, "The bitcoin address to receive the change"},
1088
+ {"changeAddress", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"pool address"}, "The peercoin address to receive the change"},
1355
1089
  {"changePosition", RPCArg::Type::NUM, RPCArg::DefaultHint{"random"}, "The index of the change output"},
1356
1090
  {"change_type", RPCArg::Type::STR, RPCArg::DefaultHint{"set by -changetype"}, "The output type to use. Only valid if changeAddress is not specified. Options are \"legacy\", \"p2sh-segwit\", and \"bech32\"."},
1357
1091
  {"includeWatching", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Also select inputs which are watch only"},
@@ -1360,7 +1094,7 @@ RPCHelpMan walletcreatefundedpsbt()
1360
1094
  {"feeRate", RPCArg::Type::AMOUNT, RPCArg::DefaultHint{"not set, fall back to wallet fee estimation"}, "Specify a fee rate in " + CURRENCY_UNIT + "/kvB."},
1361
1095
  {"subtractFeeFromOutputs", RPCArg::Type::ARR, RPCArg::Default{UniValue::VARR}, "The outputs to subtract the fee from.\n"
1362
1096
  "The fee will be equally deducted from the amount of each specified output.\n"
1363
- "Those recipients will receive less bitcoins than you enter in their corresponding amount field.\n"
1097
+ "Those recipients will receive less peercoins than you enter in their corresponding amount field.\n"
1364
1098
  "If no outputs are specified here, the sender pays the fee.",
1365
1099
  {
1366
1100
  {"vout_index", RPCArg::Type::NUM, RPCArg::Optional::OMITTED, "The zero-based output index, before a change output is added."},
@@ -1397,6 +1131,7 @@ RPCHelpMan walletcreatefundedpsbt()
1397
1131
  UniValue::VARR,
1398
1132
  UniValueType(), // ARR or OBJ, checked later
1399
1133
  UniValue::VNUM,
1134
+ UniValue::VNUM,
1400
1135
  UniValue::VOBJ,
1401
1136
  UniValue::VBOOL
1402
1137
  }, true
@@ -1406,25 +1141,19 @@ RPCHelpMan walletcreatefundedpsbt()
1406
1141
 
1407
1142
  CAmount fee;
1408
1143
  int change_position;
1409
- bool rbf{wallet.m_signal_rbf};
1410
- const UniValue &replaceable_arg = options["replaceable"];
1411
- if (!replaceable_arg.isNull()) {
1412
- RPCTypeCheckArgument(replaceable_arg, UniValue::VBOOL);
1413
- rbf = replaceable_arg.isTrue();
1414
- }
1415
- CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], rbf);
1144
+ CMutableTransaction rawTx = ConstructTransaction(request.params[0], request.params[1], request.params[2], request.params[3]);
1416
1145
  CCoinControl coin_control;
1417
1146
  // Automatically select coins, unless at least one is manually selected. Can
1418
1147
  // be overridden by options.add_inputs.
1419
1148
  coin_control.m_add_inputs = rawTx.vin.size() == 0;
1420
1149
  SetOptionsInputWeights(request.params[0], options);
1421
- FundTransaction(wallet, rawTx, fee, change_position, options, coin_control, /* override_min_fee */ true);
1150
+ FundTransaction(wallet, rawTx, fee, change_position, request.params[4], coin_control, /* override_min_fee */ true);
1422
1151
 
1423
1152
  // Make a blank psbt
1424
1153
  PartiallySignedTransaction psbtx(rawTx);
1425
1154
 
1426
1155
  // Fill transaction with out data but don't sign
1427
- bool bip32derivs = request.params[4].isNull() ? true : request.params[4].get_bool();
1156
+ bool bip32derivs = request.params[5].isNull() ? true : request.params[5].get_bool();
1428
1157
  bool complete = true;
1429
1158
  const TransactionError err{wallet.FillPSBT(psbtx, complete, 1, false, bip32derivs)};
1430
1159
  if (err != TransactionError::OK) {
src/wallet/rpc/transactions.cpp CHANGED
@@ -4,7 +4,6 @@
4
4
 
5
5
  #include <core_io.h>
6
6
  #include <key_io.h>
7
- #include <policy/rbf.h>
8
7
  #include <rpc/util.h>
9
8
  #include <util/vector.h>
10
9
  #include <wallet/receive.h>
@@ -41,17 +40,6 @@ static void WalletTxToJSON(const CWallet& wallet, const CWalletTx& wtx, UniValue
41
40
  entry.pushKV("time", wtx.GetTxTime());
42
41
  entry.pushKV("timereceived", int64_t{wtx.nTimeReceived});
43
42
 
44
- // Add opt-in RBF status
45
- std::string rbfStatus = "no";
46
- if (confirms <= 0) {
47
- RBFTransactionState rbfState = chain.isRBFOptIn(*wtx.tx);
48
- if (rbfState == RBFTransactionState::UNKNOWN)
49
- rbfStatus = "unknown";
50
- else if (rbfState == RBFTransactionState::REPLACEABLE_BIP125)
51
- rbfStatus = "yes";
52
- }
53
- entry.pushKV("bip125-replaceable", rbfStatus);
54
-
55
43
  for (const std::pair<const std::string, std::string>& item : wtx.mapValue)
56
44
  entry.pushKV(item.first, item.second);
57
45
  }
@@ -330,6 +318,16 @@ static void MaybePushAddress(UniValue & entry, const CTxDestination &dest)
330
318
  }
331
319
  }
332
320
 
321
+ static void PushCoinStakeCategory(UniValue & entry, const CWalletTx &wtx, const CWallet& wallet)
322
+ {
323
+ if (wallet.GetTxDepthInMainChain(wtx) < 1)
324
+ entry.pushKV("category", "stake-orphan");
325
+ else if (wallet.GetTxBlocksToMaturity(wtx) > 0)
326
+ entry.pushKV("category", "stake");
327
+ else
328
+ entry.pushKV("category", "stake-mint");
329
+ }
330
+
333
331
  /**
334
332
  * List transactions based on the given criteria.
335
333
  *
@@ -361,7 +359,10 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
361
359
  entry.pushKV("involvesWatchonly", true);
362
360
  }
363
361
  MaybePushAddress(entry, s.destination);
364
- entry.pushKV("category", "send");
362
+ if (wtx.IsCoinStake())
363
+ PushCoinStakeCategory(entry, wtx, wallet);
364
+ else
365
+ entry.pushKV("category", "send");
365
366
  entry.pushKV("amount", ValueFromAmount(-s.amount));
366
367
  const auto* address_book_entry = wallet.FindAddressBookEntry(s.destination);
367
368
  if (address_book_entry) {
@@ -402,6 +403,10 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
402
403
  else
403
404
  entry.pushKV("category", "generate");
404
405
  }
406
+ else if (wtx.IsCoinStake())
407
+ {
408
+ PushCoinStakeCategory(entry, wtx, wallet);
409
+ }
405
410
  else
406
411
  {
407
412
  entry.pushKV("category", "receive");
@@ -418,7 +423,6 @@ static void ListTransactions(const CWallet& wallet, const CWalletTx& wtx, int nM
418
423
  }
419
424
  }
420
425
 
421
-
422
426
  static const std::vector<RPCResult> TransactionDescriptionString()
423
427
  {
424
428
  return{{RPCResult::Type::NUM, "confirmations", "The number of confirmations for the transaction. Negative confirmations means the\n"
@@ -435,8 +439,6 @@ static const std::vector<RPCResult> TransactionDescriptionString()
435
439
  {
436
440
  {RPCResult::Type::STR_HEX, "txid", "The transaction id."},
437
441
  }},
438
- {RPCResult::Type::STR_HEX, "replaced_by_txid", /*optional=*/true, "The txid if this tx was replaced."},
439
- {RPCResult::Type::STR_HEX, "replaces_txid", /*optional=*/true, "The txid if the tx replaces one."},
440
442
  {RPCResult::Type::STR, "comment", /*optional=*/true, ""},
441
443
  {RPCResult::Type::STR, "to", /*optional=*/true, "If a comment to is associated with the transaction."},
442
444
  {RPCResult::Type::NUM_TIME, "time", "The transaction time expressed in " + UNIX_EPOCH_TIME + "."},
@@ -567,8 +569,7 @@ RPCHelpMan listsinceblock()
567
569
  {"blockhash", RPCArg::Type::STR, RPCArg::Optional::OMITTED_NAMED_ARG, "If set, the block hash to list transactions since, otherwise list all transactions."},
568
570
  {"target_confirmations", RPCArg::Type::NUM, RPCArg::Default{1}, "Return the nth block hash from the main chain. e.g. 1 would mean the best block hash. Note: this is not used as a filter, but only affects [lastblock] in the return value"},
569
571
  {"include_watchonly", RPCArg::Type::BOOL, RPCArg::DefaultHint{"true for watch-only wallets, otherwise false"}, "Include transactions to watch-only addresses (see 'importaddress')"},
570
- {"include_removed", RPCArg::Type::BOOL, RPCArg::Default{true}, "Show transactions that were removed due to a reorg in the \"removed\" array\n"
571
- "(not guaranteed to work on pruned nodes)"},
572
+ {"include_removed", RPCArg::Type::BOOL, RPCArg::Default{true}, "Show transactions that were removed due to a reorg in the \"removed\" array"},
572
573
  },
573
574
  RPCResult{
574
575
  RPCResult::Type::OBJ, "", "",
@@ -908,7 +909,7 @@ RPCHelpMan rescanblockchain()
908
909
 
909
910
  // We can't rescan beyond non-pruned blocks, stop and throw an error
910
911
  if (!pwallet->chain().hasBlocks(pwallet->GetLastBlockHash(), start_height, stop_height)) {
911
- throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height.");
912
+ throw JSONRPCError(RPC_MISC_ERROR, "Can't rescan beyond pruned data. Use RPC call getblockchaininfo to determine your pruned height."); // peercoin: should never happen
912
913
  }
913
914
 
914
915
  CHECK_NONFATAL(pwallet->chain().findAncestorByHeight(pwallet->GetLastBlockHash(), start_height, FoundBlock().hash(start_block)));
src/wallet/rpc/util.cpp CHANGED
@@ -82,6 +82,9 @@ void EnsureWalletIsUnlocked(const CWallet& wallet)
82
82
  if (wallet.IsLocked()) {
83
83
  throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Please enter the wallet passphrase with walletpassphrase first.");
84
84
  }
85
+ if (fWalletUnlockMintOnly) {
86
+ throw JSONRPCError(RPC_WALLET_UNLOCK_NEEDED, "Error: Wallet unlocked for block minting only.");
87
+ }
85
88
  }
86
89
 
87
90
  WalletContext& EnsureWalletContext(const std::any& context)
src/wallet/rpc/wallet.cpp CHANGED
@@ -4,9 +4,12 @@
4
4
  // file COPYING or http://www.opensource.org/licenses/mit-license.php.
5
5
 
6
6
  #include <core_io.h>
7
+ //#include <interfaces/wallet.h>
7
8
  #include <key_io.h>
8
9
  #include <rpc/server.h>
10
+ #include <rpc/server_util.h>
9
11
  #include <rpc/util.h>
12
+ #include <timedata.h>
10
13
  #include <util/translation.h>
11
14
  #include <wallet/receive.h>
12
15
  #include <wallet/rpc/wallet.h>
@@ -17,6 +20,11 @@
17
20
 
18
21
  #include <univalue.h>
19
22
 
23
+ #include <kernelrecord.h>
24
+ #include <node/miner.h>
25
+ #include <boost/lexical_cast.hpp>
26
+
27
+ using wallet::WalletContext;
20
28
 
21
29
  namespace wallet {
22
30
  /** Checks if a CKey is in the given CWallet compressed or otherwise*/
@@ -105,8 +113,8 @@ static RPCHelpMan getwalletinfo()
105
113
  }
106
114
  if (pwallet->IsCrypted()) {
107
115
  obj.pushKV("unlocked_until", pwallet->nRelockTime);
116
+ obj.pushKV("unlocked_minting_only", fWalletUnlockMintOnly);
108
117
  }
109
- obj.pushKV("paytxfee", ValueFromAmount(pwallet->m_pay_tx_fee.GetFeePerK()));
110
118
  obj.pushKV("private_keys_enabled", !pwallet->IsWalletFlagSet(WALLET_FLAG_DISABLE_PRIVATE_KEYS));
111
119
  obj.pushKV("avoid_reuse", pwallet->IsWalletFlagSet(WALLET_FLAG_AVOID_REUSE));
112
120
  if (pwallet->IsScanning()) {
@@ -196,7 +204,7 @@ static RPCHelpMan loadwallet()
196
204
  {
197
205
  return RPCHelpMan{"loadwallet",
198
206
  "\nLoads a wallet from a wallet file or directory."
199
- "\nNote that all wallet command-line options used when starting bitcoind will be"
207
+ "\nNote that all wallet command-line options used when starting peercoind will be"
200
208
  "\napplied to the new wallet.\n",
201
209
  {
202
210
  {"filename", RPCArg::Type::STR, RPCArg::Optional::NO, "The wallet directory or .dat file."},
@@ -450,6 +458,254 @@ static RPCHelpMan unloadwallet()
450
458
  };
451
459
  }
452
460
 
461
+ static RPCHelpMan importcoinstake()
462
+ {
463
+ return RPCHelpMan{"importcoinstake",
464
+ "Import presigned coinstake for use in minting.\n",
465
+ {
466
+ {"coinstake", RPCArg::Type::STR_HEX, RPCArg::DefaultHint{"signed coinstake"}, "signed coinstake transaction as hex."},
467
+ {"timestamp", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "timestamp when this coinstake will be valid."},
468
+ },
469
+ RPCResult{RPCResult::Type::OBJ, "", "", {
470
+ {RPCResult::Type::STR, "txid", "transaction id if import is successful."},
471
+ {RPCResult::Type::NUM, "nTime", "timestamp when coinstake is due to mint."},
472
+ }},
473
+ RPCExamples{
474
+ HelpExampleCli("importcoinstake", "03000000")
475
+ + HelpExampleRpc("importcoinstake", "03000000")
476
+ },
477
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
478
+ {
479
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
480
+ CWallet* const pwallet = wallet.get();
481
+
482
+ RPCTypeCheck(request.params, {
483
+ UniValue::VSTR,
484
+ UniValue::VNUM
485
+ });
486
+
487
+ // parse hex string from parameter
488
+ CMutableTransaction mtx;
489
+ if (!DecodeHexTx(mtx, request.params[0].get_str()))
490
+ throw JSONRPCError(RPC_DESERIALIZATION_ERROR, "TX decode failed");
491
+ CTransactionRef tx(MakeTransactionRef(std::move(mtx)));
492
+
493
+ std::string err_string;
494
+ AssertLockNotHeld(cs_main);
495
+
496
+ {
497
+ int timestamp;
498
+ if (!request.params[1].isNull())
499
+ timestamp = request.params[1].get_int();
500
+ else
501
+ timestamp = tx->nTime;
502
+
503
+ if (timestamp < GetTime()) {
504
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "Expired coinstake");
505
+ }
506
+
507
+ // check if we have the key to vout[1]
508
+ std::set<ScriptPubKeyMan*> spk_mans = pwallet->GetScriptPubKeyMans(tx->vout[1].scriptPubKey);
509
+ if (spk_mans.size() == 0) {
510
+ throw JSONRPCError(RPC_INVALID_PARAMETER, "No keys for vout[1]");
511
+ }
512
+
513
+ // add to in memory structure
514
+ pwallet->m_coinstakes[timestamp] = tx;
515
+ }
516
+ UniValue result(UniValue::VOBJ);
517
+ result.pushKV("txid", tx->GetHash().GetHex());
518
+ result.pushKV("nTime", int(tx->nTime));
519
+ return result;
520
+ },
521
+ };
522
+ }
523
+
524
+
525
+ static RPCHelpMan listminting()
526
+ {
527
+ return RPCHelpMan{"listminting",
528
+ "Return all mintable outputs and provide details for each of them.\n",
529
+ {
530
+ {"count", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "maximum number of outputs to be returned."},
531
+ },
532
+ RPCResult{
533
+ RPCResult::Type::ARR, "", "",
534
+ {
535
+ {RPCResult::Type::OBJ, "", "",
536
+ {
537
+ {RPCResult::Type::STR, "address", "Address of the output"},
538
+ {RPCResult::Type::STR, "input-txid", "Transaction id"},
539
+ {RPCResult::Type::NUM, "time", "Time of transaction"},
540
+ {RPCResult::Type::NUM, "amount", "Amount of transaction output"},
541
+ {RPCResult::Type::STR, "status", "Status of transaction output"},
542
+ {RPCResult::Type::NUM, "age-in-day", "Age of transaction in days"},
543
+ {RPCResult::Type::NUM, "coin-day-weight", "Weight of transaction output"},
544
+ {RPCResult::Type::NUM, "proof-of-stake-difficulty", "Current proof of stake difficulty"},
545
+ {RPCResult::Type::NUM, "minting-probability-10min", "Probability of minting in next 10 minutes"},
546
+ {RPCResult::Type::NUM, "minting-probability-24h", "Probability of minting in next 24 hours"},
547
+ {RPCResult::Type::NUM, "minting-probability-30d", "Probability of minting in next 30 days"},
548
+ {RPCResult::Type::NUM, "minting-probability-90d", "Probability of minting in next 90 days"},
549
+ {RPCResult::Type::NUM, "search-interval-in-sec", "Interval between last minting attempts"},
550
+ {RPCResult::Type::NUM, "attempts", "Number of seconds since maturity"},
551
+ }},
552
+ }
553
+ },
554
+ RPCExamples{
555
+ HelpExampleCli("listminting", "10")
556
+ + HelpExampleRpc("listminting", "10")
557
+ },
558
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
559
+ {
560
+ WalletContext& context = EnsureWalletContext(request.context);
561
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
562
+ CWallet* const pwallet = wallet.get();
563
+
564
+ RPCTypeCheck(request.params, {
565
+ UniValue::VNUM
566
+ });
567
+
568
+ int64_t count=-1;
569
+ if (!request.params[0].isNull())
570
+ count = request.params[0].get_int();
571
+
572
+ UniValue ret(UniValue::VARR);
573
+
574
+ const CBlockIndex *p = GetLastBlockIndex(context.chain->chainman().ActiveChain().Tip(), true);
575
+ double difficulty = p->GetBlockDifficulty();
576
+ int64_t nStakeMinAge = Params().GetConsensus().nStakeMinAge;
577
+
578
+ std::unique_ptr<interfaces::Wallet> iwallet = interfaces::MakeWallet(context,wallet);
579
+ const auto& vwtx = iwallet->getWalletTxs();
580
+ for(const auto& wtx : vwtx) {
581
+ std::vector<KernelRecord> txList = KernelRecord::decomposeOutput(*iwallet, wtx);
582
+
583
+ int64_t minAge = nStakeMinAge / 60 / 60 / 24;
584
+ for (auto& kr : txList) {
585
+ if(!kr.spent) {
586
+
587
+ if(count > 0 && (int32_t)ret.size() >= count) {
588
+ break;
589
+ }
590
+
591
+ std::string strTime = boost::lexical_cast<std::string>(kr.nTime);
592
+ std::string strAmount = boost::lexical_cast<std::string>(kr.nValue);
593
+ std::string strAge = boost::lexical_cast<std::string>(kr.getAge());
594
+ std::string strCoinAge = boost::lexical_cast<std::string>(kr.getCoinAge());
595
+
596
+ // JSONRPCRequest request2;
597
+ // request2.params = UniValue(UniValue::VARR);
598
+ // request2.params.push_back(kr.address);
599
+ // std::string account = AccountFromValue(getaccount(request2));
600
+
601
+ std::string status = "immature";
602
+ int searchInterval = 0;
603
+ int attemps = 0;
604
+ if(kr.getAge() >= minAge)
605
+ {
606
+ status = "mature";
607
+ searchInterval = (int)nLastCoinStakeSearchInterval;
608
+ attemps = GetAdjustedTime() - kr.nTime - nStakeMinAge;
609
+ }
610
+
611
+ UniValue obj(UniValue::VOBJ);
612
+ // obj.push_back(Pair("account", account));
613
+ obj.pushKV("address", kr.address);
614
+ obj.pushKV("input-txid", kr.hash.ToString());
615
+ obj.pushKV("time", strTime);
616
+ obj.pushKV("amount", strAmount);
617
+ obj.pushKV("status", status);
618
+ obj.pushKV("age-in-day", strAge);
619
+ obj.pushKV("coin-day-weight", strCoinAge);
620
+ obj.pushKV("proof-of-stake-difficulty", difficulty);
621
+ obj.pushKV("minting-probability-10min", kr.getProbToMintWithinNMinutes(difficulty, 10));
622
+ obj.pushKV("minting-probability-24h", kr.getProbToMintWithinNMinutes(difficulty, 60*24));
623
+ obj.pushKV("minting-probability-30d", kr.getProbToMintWithinNMinutes(difficulty, 60*24*30));
624
+ obj.pushKV("minting-probability-90d", kr.getProbToMintWithinNMinutes(difficulty, 60*24*90));
625
+ obj.pushKV("search-interval-in-sec", searchInterval);
626
+ obj.pushKV("attempts", attemps);
627
+ ret.push_back(obj);
628
+ }
629
+ }
630
+ }
631
+
632
+ if (pwallet->m_coinstakes.size()) {
633
+ for (const auto& [timestamp, txn] : pwallet->m_coinstakes) {
634
+ UniValue obj(UniValue::VOBJ);
635
+ CTxDestination address;
636
+ ExtractDestination(txn->vout[1].scriptPubKey, address);
637
+ obj.pushKV("address", EncodeDestination(address));
638
+ obj.pushKV("amount", ValueFromAmount(txn->vout[1].nValue));
639
+ obj.pushKV("status", "imported");
640
+ obj.pushKV("time", (uint64_t)txn->nTime);
641
+ obj.pushKV("due-in-seconds", (uint64_t)(txn->nTime - GetAdjustedTime()));
642
+ ret.push_back(obj);
643
+ }
644
+ }
645
+ return ret;
646
+ },
647
+ };
648
+ }
649
+
650
+ static RPCHelpMan reservebalance()
651
+ {
652
+ return RPCHelpMan{"reservebalance",
653
+ "Set reserve amount not participating in network protection.\n",
654
+ {
655
+ {"reserve", RPCArg::Type::BOOL, RPCArg::Optional::OMITTED_NAMED_ARG, "turn balance reserve on or off."},
656
+ {"amount", RPCArg::Type::NUM, RPCArg::Optional::OMITTED_NAMED_ARG, "amount of peercoin to be reserved."},
657
+ },
658
+ RPCResult{RPCResult::Type::OBJ, "", "", {
659
+ {RPCResult::Type::STR, "reserve", "status of reserve."},
660
+ }},
661
+ RPCExamples{
662
+ HelpExampleCli("reservebalance", "true 10")
663
+ + HelpExampleRpc("reservebalance", "true 10")
664
+ },
665
+ [&](const RPCHelpMan& self, const JSONRPCRequest& request) -> UniValue
666
+ {
667
+ std::shared_ptr<CWallet> const wallet = GetWalletForJSONRPCRequest(request);
668
+ CWallet* const pwallet = wallet.get();
669
+
670
+ EnsureWalletIsUnlocked(*pwallet);
671
+
672
+ RPCTypeCheck(request.params, {
673
+ UniValue::VBOOL,
674
+ UniValue::VNUM
675
+ });
676
+
677
+ if (request.params.size() > 0)
678
+ {
679
+ bool fReserve = request.params[0].get_bool();
680
+ if (fReserve)
681
+ {
682
+ if (request.params.size() == 1)
683
+ throw std::runtime_error("must provide amount to reserve balance.\n");
684
+ int64_t nAmount = AmountFromValue(request.params[1]);
685
+ nAmount = (nAmount / CENT) * CENT; // round to cent
686
+ if (nAmount < 0)
687
+ throw std::runtime_error("amount cannot be negative.\n");
688
+ gArgs.ForceSetArg("-reservebalance", FormatMoney(nAmount));
689
+ }
690
+ else
691
+ {
692
+ if (request.params.size() > 1)
693
+ throw std::runtime_error("cannot specify amount to turn off reserve.\n");
694
+ gArgs.ForceSetArg("-reservebalance", "0");
695
+ }
696
+ }
697
+
698
+ UniValue result(UniValue::VOBJ);
699
+ std::optional<CAmount> nReserveBalance = ParseMoney(gArgs.GetArg("-reservebalance", ""));
700
+ if (gArgs.IsArgSet("-reservebalance") && !nReserveBalance)
701
+ throw std::runtime_error("invalid reserve balance amount\n");
702
+ result.pushKV("reserve", (nReserveBalance > 0));
703
+ result.pushKV("amount", nReserveBalance.value());
704
+ return result;
705
+ },
706
+ };
707
+ }
708
+
453
709
  static RPCHelpMan sethdseed()
454
710
  {
455
711
  return RPCHelpMan{"sethdseed",
@@ -607,8 +863,6 @@ RPCHelpMan importaddress();
607
863
  RPCHelpMan importpubkey();
608
864
  RPCHelpMan dumpwallet();
609
865
  RPCHelpMan importwallet();
610
- RPCHelpMan importprunedfunds();
611
- RPCHelpMan removeprunedfunds();
612
866
  RPCHelpMan importmulti();
613
867
  RPCHelpMan importdescriptors();
614
868
  RPCHelpMan listdescriptors();
@@ -634,10 +888,7 @@ RPCHelpMan encryptwallet();
634
888
  // spend
635
889
  RPCHelpMan sendtoaddress();
636
890
  RPCHelpMan sendmany();
637
- RPCHelpMan settxfee();
638
891
  RPCHelpMan fundrawtransaction();
639
- RPCHelpMan bumpfee();
640
- RPCHelpMan psbtbumpfee();
641
892
  RPCHelpMan send();
642
893
  RPCHelpMan walletprocesspsbt();
643
894
  RPCHelpMan walletcreatefundedpsbt();
@@ -667,8 +918,6 @@ static const CRPCCommand commands[] =
667
918
  { "wallet", &abortrescan, },
668
919
  { "wallet", &addmultisigaddress, },
669
920
  { "wallet", &backupwallet, },
670
- { "wallet", &bumpfee, },
671
- { "wallet", &psbtbumpfee, },
672
921
  { "wallet", &createwallet, },
673
922
  { "wallet", &restorewallet, },
674
923
  { "wallet", &dumpprivkey, },
@@ -689,7 +938,6 @@ static const CRPCCommand commands[] =
689
938
  { "wallet", &importdescriptors, },
690
939
  { "wallet", &importmulti, },
691
940
  { "wallet", &importprivkey, },
692
- { "wallet", &importprunedfunds, },
693
941
  { "wallet", &importpubkey, },
694
942
  { "wallet", &importwallet, },
695
943
  { "wallet", &keypoolrefill, },
@@ -707,14 +955,12 @@ static const CRPCCommand commands[] =
707
955
  { "wallet", &loadwallet, },
708
956
  { "wallet", &lockunspent, },
709
957
  { "wallet", &newkeypool, },
710
- { "wallet", &removeprunedfunds, },
711
958
  { "wallet", &rescanblockchain, },
712
959
  { "wallet", &send, },
713
960
  { "wallet", &sendmany, },
714
961
  { "wallet", &sendtoaddress, },
715
962
  { "wallet", &sethdseed, },
716
963
  { "wallet", &setlabel, },
717
- { "wallet", &settxfee, },
718
964
  { "wallet", &setwalletflag, },
719
965
  { "wallet", &signmessage, },
720
966
  { "wallet", &signrawtransactionwithwallet, },
@@ -728,6 +974,10 @@ static const CRPCCommand commands[] =
728
974
  { "wallet", &walletpassphrase, },
729
975
  { "wallet", &walletpassphrasechange, },
730
976
  { "wallet", &walletprocesspsbt, },
977
+ // peercoin commands
978
+ { "wallet", &importcoinstake, },
979
+ { "wallet", &listminting, },
980
+ { "wallet", &reservebalance, },
731
981
  };
732
982
  // clang-format on
733
983
  return commands;
src/wallet/spend.cpp CHANGED
@@ -7,13 +7,13 @@
7
7
  #include <interfaces/chain.h>
8
8
  #include <policy/policy.h>
9
9
  #include <script/signingprovider.h>
10
+ #include <timedata.h>
10
11
  #include <util/check.h>
11
12
  #include <util/fees.h>
12
13
  #include <util/moneystr.h>
13
14
  #include <util/rbf.h>
14
15
  #include <util/translation.h>
15
16
  #include <wallet/coincontrol.h>
16
- #include <wallet/fees.h>
17
17
  #include <wallet/receive.h>
18
18
  #include <wallet/spend.h>
19
19
  #include <wallet/transaction.h>
@@ -119,37 +119,6 @@ void AvailableCoins(const CWallet& wallet, std::vector<COutput>& vCoins, const C
119
119
 
120
120
  bool safeTx = CachedTxIsTrusted(wallet, wtx, trusted_parents);
121
121
 
122
- // We should not consider coins from transactions that are replacing
123
- // other transactions.
124
- //
125
- // Example: There is a transaction A which is replaced by bumpfee
126
- // transaction B. In this case, we want to prevent creation of
127
- // a transaction B' which spends an output of B.
128
- //
129
- // Reason: If transaction A were initially confirmed, transactions B
130
- // and B' would no longer be valid, so the user would have to create
131
- // a new transaction C to replace B'. However, in the case of a
132
- // one-block reorg, transactions B' and C might BOTH be accepted,
133
- // when the user only wanted one of them. Specifically, there could
134
- // be a 1-block reorg away from the chain where transactions A and C
135
- // were accepted to another chain where B, B', and C were all
136
- // accepted.
137
- if (nDepth == 0 && wtx.mapValue.count("replaces_txid")) {
138
- safeTx = false;
139
- }
140
-
141
- // Similarly, we should not consider coins from transactions that
142
- // have been replaced. In the example above, we would want to prevent
143
- // creation of a transaction A' spending an output of A, because if
144
- // transaction B were initially confirmed, conflicting with A and
145
- // A', we wouldn't want to the user to create a transaction D
146
- // intending to replace A', but potentially resulting in a scenario
147
- // where A, A', and D could all be accepted (instead of just B and
148
- // D, or just A and A' like the user would want).
149
- if (nDepth == 0 && wtx.mapValue.count("replaced_by_txid")) {
150
- safeTx = false;
151
- }
152
-
153
122
  if (only_safe && !safeTx) {
154
123
  continue;
155
124
  }
@@ -467,7 +436,7 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vec
467
436
  if (coin.m_input_bytes == -1) {
468
437
  return std::nullopt; // Not solvable, can't estimate size for fee
469
438
  }
470
- coin.effective_value = coin.txout.nValue - coin_selection_params.m_effective_feerate.GetFee(coin.m_input_bytes);
439
+ coin.effective_value = coin.txout.nValue - GetMinFee(coin.m_input_bytes, GetAdjustedTime());
471
440
  if (coin_selection_params.m_subtract_fee_outputs) {
472
441
  value_to_select -= coin.txout.nValue;
473
442
  } else {
@@ -636,7 +605,7 @@ static bool CreateTransactionInternal(
636
605
  int& nChangePosInOut,
637
606
  bilingual_str& error,
638
607
  const CCoinControl& coin_control,
639
- FeeCalculation& fee_calc_out,
608
+ CAmount& fee_calc_out,
640
609
  bool sign) EXCLUSIVE_LOCKS_REQUIRED(wallet.cs_wallet)
641
610
  {
642
611
  AssertLockHeld(wallet.cs_wallet);
@@ -647,9 +616,6 @@ static bool CreateTransactionInternal(
647
616
  CoinSelectionParams coin_selection_params; // Parameters for coin selection, init with dummy
648
617
  coin_selection_params.m_avoid_partial_spends = coin_control.m_avoid_partial_spends;
649
618
 
650
- // Set the long term feerate estimate to the wallet's consolidate feerate
651
- coin_selection_params.m_long_term_feerate = wallet.m_consolidate_feerate;
652
-
653
619
  CAmount recipients_sum = 0;
654
620
  const OutputType change_type = wallet.TransactionChangeType(coin_control.m_change_type ? *coin_control.m_change_type : wallet.m_default_change_type, vecSend);
655
621
  ReserveDestination reservedest(&wallet, change_type);
@@ -691,7 +657,7 @@ static bool CreateTransactionInternal(
691
657
  CHECK_NONFATAL(IsValidDestination(dest) != scriptChange.empty());
692
658
  }
693
659
  CTxOut change_prototype_txout(0, scriptChange);
694
- coin_selection_params.change_output_size = GetSerializeSize(change_prototype_txout);
660
+ coin_selection_params.change_output_size = GetSerializeSize(change_prototype_txout, PROTOCOL_VERSION);
695
661
 
696
662
  // Get size of spending the change output
697
663
  int change_spend_size = CalculateMaximumSignedInputSize(change_prototype_txout, &wallet);
@@ -703,31 +669,13 @@ static bool CreateTransactionInternal(
703
669
  coin_selection_params.change_spend_size = (size_t)change_spend_size;
704
670
  }
705
671
 
706
- // Set discard feerate
707
- coin_selection_params.m_discard_feerate = GetDiscardRate(wallet);
708
-
709
- // Get the fee rate to use effective values in coin selection
710
- FeeCalculation feeCalc;
711
- coin_selection_params.m_effective_feerate = GetMinimumFeeRate(wallet, coin_control, &feeCalc);
712
- // Do not, ever, assume that it's fine to change the fee rate if the user has explicitly
713
- // provided one
714
- if (coin_control.m_feerate && coin_selection_params.m_effective_feerate > *coin_control.m_feerate) {
715
- error = strprintf(_("Fee rate (%s) is lower than the minimum fee rate setting (%s)"), coin_control.m_feerate->ToString(FeeEstimateMode::SAT_VB), coin_selection_params.m_effective_feerate.ToString(FeeEstimateMode::SAT_VB));
716
- return false;
717
- }
718
- if (feeCalc.reason == FeeReason::FALLBACK && !wallet.m_allow_fallback_fee) {
719
- // eventually allow a fallback fee
720
- error = _("Fee estimation failed. Fallbackfee is disabled. Wait a few blocks or enable -fallbackfee.");
721
- return false;
722
- }
723
-
724
672
  // Calculate the cost of change
725
673
  // Cost of change is the cost of creating the change output + cost of spending the change output in the future.
726
674
  // For creating the change output now, we use the effective feerate.
727
675
  // For spending the change output in the future, we use the discard feerate for now.
728
676
  // So cost of change = (change output size * effective feerate) + (size of spending change output * discard feerate)
729
- coin_selection_params.m_change_fee = coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.change_output_size);
730
- coin_selection_params.m_cost_of_change = coin_selection_params.m_discard_feerate.GetFee(coin_selection_params.change_spend_size) + coin_selection_params.m_change_fee;
677
+ coin_selection_params.m_change_fee = GetMinFee(coin_selection_params.change_output_size, GetAdjustedTime());
678
+ coin_selection_params.m_cost_of_change = GetMinFee(coin_selection_params.change_spend_size, GetAdjustedTime()) + coin_selection_params.m_change_fee;
731
679
 
732
680
  // vouts to the payees
733
681
  if (!coin_selection_params.m_subtract_fee_outputs) {
@@ -742,7 +690,7 @@ static bool CreateTransactionInternal(
742
690
  coin_selection_params.tx_noinputs_size += ::GetSerializeSize(txout, PROTOCOL_VERSION);
743
691
  }
744
692
 
745
- if (IsDust(txout, wallet.chain().relayDustFee()))
693
+ if (recipient.nAmount < MIN_TXOUT_AMOUNT)
746
694
  {
747
695
  error = _("Transaction amount too small");
748
696
  return false;
@@ -751,7 +699,7 @@ static bool CreateTransactionInternal(
751
699
  }
752
700
 
753
701
  // Include the fees for things that aren't inputs, excluding the change output
754
- const CAmount not_input_fees = coin_selection_params.m_effective_feerate.GetFee(coin_selection_params.tx_noinputs_size);
702
+ const CAmount not_input_fees = coin_selection_params.tx_noinputs_size ? GetMinFee(coin_selection_params.tx_noinputs_size, GetAdjustedTime()) : 0;
755
703
  CAmount selection_target = recipients_sum + not_input_fees;
756
704
 
757
705
  // Get available coins
@@ -796,7 +744,7 @@ static bool CreateTransactionInternal(
796
744
  // to avoid conflicting with other possible uses of nSequence,
797
745
  // and in the spirit of "smallest possible change from prior
798
746
  // behavior."
799
- const uint32_t nSequence{coin_control.m_signal_bip125_rbf.value_or(wallet.m_signal_rbf) ? MAX_BIP125_RBF_SEQUENCE : CTxIn::MAX_SEQUENCE_NONFINAL};
747
+ const uint32_t nSequence{CTxIn::MAX_SEQUENCE_NONFINAL};
800
748
  for (const auto& coin : selected_coins) {
801
749
  txNew.vin.push_back(CTxIn(coin.outpoint, CScript(), nSequence));
802
750
  }
@@ -808,7 +756,7 @@ static bool CreateTransactionInternal(
808
756
  error = _("Missing solving data for estimating transaction size");
809
757
  return false;
810
758
  }
811
- nFeeRet = coin_selection_params.m_effective_feerate.GetFee(nBytes);
759
+ nFeeRet = GetMinFee(nBytes, GetAdjustedTime());
812
760
 
813
761
  // Subtract fee from the change output if not subtracting it from recipient outputs
814
762
  CAmount fee_needed = nFeeRet;
@@ -820,7 +768,7 @@ static bool CreateTransactionInternal(
820
768
  // 1. The change output would be dust
821
769
  // 2. The change is within the (almost) exact match window, i.e. it is less than or equal to the cost of the change output (cost_of_change)
822
770
  CAmount change_amount = change_position->nValue;
823
- if (IsDust(*change_position, coin_selection_params.m_discard_feerate) || change_amount <= coin_selection_params.m_cost_of_change)
771
+ if ((change_amount < MIN_TXOUT_AMOUNT) || change_amount <= coin_selection_params.m_cost_of_change)
824
772
  {
825
773
  nChangePosInOut = -1;
826
774
  change_amount = 0;
@@ -829,7 +777,7 @@ static bool CreateTransactionInternal(
829
777
  // Because we have dropped this change, the tx size and required fee will be different, so let's recalculate those
830
778
  tx_sizes = CalculateMaximumSignedTxSize(CTransaction(txNew), &wallet, &coin_control);
831
779
  nBytes = tx_sizes.vsize;
832
- fee_needed = coin_selection_params.m_effective_feerate.GetFee(nBytes);
780
+ fee_needed = GetMinFee(nBytes, GetAdjustedTime());
833
781
  }
834
782
 
835
783
  // The only time that fee_needed should be less than the amount available for fees (in change_and_fee - change_amount) is when
@@ -864,7 +812,7 @@ static bool CreateTransactionInternal(
864
812
  }
865
813
 
866
814
  // Error if this output is reduced to be below dust
867
- if (IsDust(txout, wallet.chain().relayDustFee())) {
815
+ if (txout.nValue < MIN_TXOUT_AMOUNT) {
868
816
  if (txout.nValue < 0) {
869
817
  error = _("The transaction amount is too small to pay the fee");
870
818
  } else {
@@ -899,11 +847,6 @@ static bool CreateTransactionInternal(
899
847
  return false;
900
848
  }
901
849
 
902
- if (nFeeRet > wallet.m_default_max_tx_fee) {
903
- error = TransactionErrorString(TransactionError::MAX_FEE_EXCEEDED);
904
- return false;
905
- }
906
-
907
850
  if (gArgs.GetBoolArg("-walletrejectlongchains", DEFAULT_WALLET_REJECT_LONG_CHAINS)) {
908
851
  // Lastly, ensure this tx will pass the mempool's chain limits
909
852
  if (!wallet.chain().checkChainLimits(tx)) {
@@ -915,16 +858,8 @@ static bool CreateTransactionInternal(
915
858
  // Before we return success, we assume any change key will be used to prevent
916
859
  // accidental re-use.
917
860
  reservedest.KeepDestination();
918
- fee_calc_out = feeCalc;
919
-
920
- wallet.WalletLogPrintf("Fee Calculation: Fee:%d Bytes:%u Tgt:%d (requested %d) Reason:\"%s\" Decay %.5f: Estimation: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out) Fail: (%g - %g) %.2f%% %.1f/(%.1f %d mem %.1f out)\n",
921
- nFeeRet, nBytes, feeCalc.returnedTarget, feeCalc.desiredTarget, StringForFeeReason(feeCalc.reason), feeCalc.est.decay,
922
- feeCalc.est.pass.start, feeCalc.est.pass.end,
923
- (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool) > 0.0 ? 100 * feeCalc.est.pass.withinTarget / (feeCalc.est.pass.totalConfirmed + feeCalc.est.pass.inMempool + feeCalc.est.pass.leftMempool) : 0.0,
924
- feeCalc.est.pass.withinTarget, feeCalc.est.pass.totalConfirmed, feeCalc.est.pass.inMempool, feeCalc.est.pass.leftMempool,
925
- feeCalc.est.fail.start, feeCalc.est.fail.end,
926
- (feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool) > 0.0 ? 100 * feeCalc.est.fail.withinTarget / (feeCalc.est.fail.totalConfirmed + feeCalc.est.fail.inMempool + feeCalc.est.fail.leftMempool) : 0.0,
927
- feeCalc.est.fail.withinTarget, feeCalc.est.fail.totalConfirmed, feeCalc.est.fail.inMempool, feeCalc.est.fail.leftMempool);
861
+
862
+ wallet.WalletLogPrintf("Fee Calculation: Fee:%d Bytes:%u Needed:%d\n", nFeeRet, nBytes, fee_needed);
928
863
  return true;
929
864
  }
930
865
 
@@ -936,7 +871,7 @@ bool CreateTransaction(
936
871
  int& nChangePosInOut,
937
872
  bilingual_str& error,
938
873
  const CCoinControl& coin_control,
939
- FeeCalculation& fee_calc_out,
874
+ CAmount& fee_calc_out,
940
875
  bool sign)
941
876
  {
942
877
  if (vecSend.empty()) {
@@ -998,7 +933,7 @@ bool FundTransaction(CWallet& wallet, CMutableTransaction& tx, CAmount& nFeeRet,
998
933
  LOCK(wallet.cs_wallet);
999
934
 
1000
935
  CTransactionRef tx_new;
1001
- FeeCalculation fee_calc_out;
936
+ CAmount fee_calc_out;
1002
937
  if (!CreateTransaction(wallet, vecSend, tx_new, nFeeRet, nChangePosInOut, error, coinControl, fee_calc_out, false)) {
1003
938
  return false;
1004
939
  }
src/wallet/spend.h CHANGED
@@ -136,7 +136,7 @@ std::optional<SelectionResult> SelectCoins(const CWallet& wallet, const std::vec
136
136
  * selected by SelectCoins(); Also create the change output, when needed
137
137
  * @note passing nChangePosInOut as -1 will result in setting a random position
138
138
  */
139
- bool CreateTransaction(CWallet& wallet, const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, const CCoinControl& coin_control, FeeCalculation& fee_calc_out, bool sign = true);
139
+ bool CreateTransaction(CWallet& wallet, const std::vector<CRecipient>& vecSend, CTransactionRef& tx, CAmount& nFeeRet, int& nChangePosInOut, bilingual_str& error, const CCoinControl& coin_control, CAmount& fee_calc_out, bool sign = true);
140
140
 
141
141
  /**
142
142
  * Insert additional inputs into the transaction by
src/wallet/transaction.cpp CHANGED
@@ -21,6 +21,10 @@ bool CWalletTx::InMempool() const
21
21
 
22
22
  int64_t CWalletTx::GetTxTime() const
23
23
  {
24
+ // peercoin: we still have the timestamp, so use it to avoid confusion
25
+ if (tx->nTime)
26
+ return tx->nTime;
27
+
24
28
  int64_t n = nTimeSmart;
25
29
  return n ? n : nTimeReceived;
26
30
  }
src/wallet/transaction.h CHANGED
@@ -145,10 +145,6 @@ public:
145
145
  *
146
146
  * "comment", "to" - comment strings provided to sendtoaddress,
147
147
  * and sendmany wallet RPCs
148
- * "replaces_txid" - txid (as HexStr) of transaction replaced by
149
- * bumpfee on transaction created by bumpfee
150
- * "replaced_by_txid" - txid (as HexStr) of transaction created by
151
- * bumpfee on transaction replaced by bumpfee
152
148
  * "from", "message" - obsolete fields that could be set in UI prior to
153
149
  * 2011 (removed in commit 4d9b223)
154
150
  *
@@ -297,6 +293,7 @@ public:
297
293
  bool isConfirmed() const { return state<TxStateConfirmed>(); }
298
294
  const uint256& GetHash() const { return tx->GetHash(); }
299
295
  bool IsCoinBase() const { return tx->IsCoinBase(); }
296
+ bool IsCoinStake() const { return tx->IsCoinStake(); }
300
297
 
301
298
  // Disable copying of CWalletTx objects to prevent bugs where instances get
302
299
  // copied in and out of the mapWallet map, and fields are updated in the
src/wallet/wallet.cpp CHANGED
@@ -9,14 +9,15 @@
9
9
  #include <consensus/amount.h>
10
10
  #include <consensus/consensus.h>
11
11
  #include <consensus/validation.h>
12
+ #include <consensus/tx_verify.h>
12
13
  #include <external_signer.h>
13
14
  #include <fs.h>
15
+ #include <index/txindex.h>
14
16
  #include <interfaces/chain.h>
15
17
  #include <interfaces/wallet.h>
16
18
  #include <key.h>
17
19
  #include <key_io.h>
18
20
  #include <outputtype.h>
19
- #include <policy/fees.h>
20
21
  #include <policy/policy.h>
21
22
  #include <primitives/block.h>
22
23
  #include <primitives/transaction.h>
@@ -24,18 +25,22 @@
24
25
  #include <script/descriptor.h>
25
26
  #include <script/script.h>
26
27
  #include <script/signingprovider.h>
28
+ #include <timedata.h>
27
29
  #include <txmempool.h>
28
30
  #include <util/bip32.h>
29
31
  #include <util/check.h>
30
32
  #include <util/error.h>
31
- #include <util/fees.h>
32
33
  #include <util/moneystr.h>
33
- #include <util/rbf.h>
34
34
  #include <util/string.h>
35
35
  #include <util/translation.h>
36
+ #include <validation.h>
37
+ #include <bignum.h>
38
+ #include <kernel.h>
39
+ #include <txdb.h>
36
40
  #include <wallet/coincontrol.h>
37
41
  #include <wallet/context.h>
38
- #include <wallet/fees.h>
42
+ #include <wallet/receive.h>
43
+ #include <wallet/spend.h>
39
44
  #include <wallet/external_signer_scriptpubkeyman.h>
40
45
 
41
46
  #include <univalue.h>
@@ -45,6 +50,7 @@
45
50
  #include <optional>
46
51
 
47
52
  #include <boost/algorithm/string/replace.hpp>
53
+ #include <boost/foreach.hpp>
48
54
 
49
55
  using interfaces::FoundBlock;
50
56
 
@@ -370,6 +376,10 @@ std::shared_ptr<CWallet> CreateWallet(WalletContext& context, const std::string&
370
376
  return wallet;
371
377
  }
372
378
 
379
+ // peercoin: optional setting to unlock wallet for block minting only;
380
+ // serves to disable the trivial sendmoney when OS account compromised
381
+ bool fWalletUnlockMintOnly = false;
382
+
373
383
  std::shared_ptr<CWallet> RestoreWallet(WalletContext& context, const fs::path& backup_file, const std::string& wallet_name, std::optional<bool> load_on_start, DatabaseStatus& status, bilingual_str& error, std::vector<bilingual_str>& warnings)
374
384
  {
375
385
  DatabaseOptions options;
@@ -848,36 +858,29 @@ void CWallet::MarkDirty()
848
858
  }
849
859
  }
850
860
 
851
- bool CWallet::MarkReplaced(const uint256& originalHash, const uint256& newHash)
861
+ void CWallet::WalletUpdateSpent(const CTransactionRef &tx)
852
862
  {
853
- LOCK(cs_wallet);
854
-
855
- auto mi = mapWallet.find(originalHash);
856
-
857
- // There is a bug if MarkReplaced is not called on an existing wallet transaction.
858
- assert(mi != mapWallet.end());
859
-
860
- CWalletTx& wtx = (*mi).second;
861
-
862
- // Ensure for now that we're not overwriting data
863
- assert(wtx.mapValue.count("replaced_by_txid") == 0);
864
-
865
- wtx.mapValue["replaced_by_txid"] = newHash.ToString();
866
-
867
- // Refresh mempool status without waiting for transactionRemovedFromMempool
868
- RefreshMempoolStatus(wtx, chain());
869
-
870
- WalletBatch batch(GetDatabase());
871
-
872
- bool success = true;
873
- if (!batch.WriteTx(wtx)) {
874
- WalletLogPrintf("%s: Updating batch tx %s failed\n", __func__, wtx.GetHash().ToString());
875
- success = false;
863
+ // Anytime a signature is successfully verified, it's proof the outpoint is spent.
864
+ // Update the wallet spent flag if it doesn't know due to wallet.dat being
865
+ // restored from backup or the user making copies of wallet.dat.
866
+ {
867
+ LOCK(cs_wallet);
868
+ BOOST_FOREACH(const CTxIn& txin, tx->vin)
869
+ {
870
+ auto mi = mapWallet.find(txin.prevout.hash);
871
+ if (mi != mapWallet.end())
872
+ {
873
+ CWalletTx& wtx = (*mi).second;
874
+ if (txin.prevout.n >= wtx.tx->vout.size())
875
+ LogPrintf("WalletUpdateSpent: bad wtx %s\n", wtx.GetHash().ToString().c_str());
876
+ else if (IsMine(wtx.tx->vout[txin.prevout.n]))
877
+ {
878
+ LogPrintf("WalletUpdateSpent found spent coin %sppc %s\n", FormatMoney(CachedTxGetCredit(*this, wtx, ISMINE_SPENDABLE)).c_str(), wtx.GetHash().ToString().c_str());
879
+ NotifyTransactionChanged(txin.prevout.hash, CT_UPDATED);
880
+ }
881
+ }
882
+ }
876
883
  }
877
-
878
- NotifyTransactionChanged(originalHash, CT_UPDATED);
879
-
880
- return success;
881
884
  }
882
885
 
883
886
  void CWallet::SetSpentKeyState(WalletBatch& batch, const uint256& hash, unsigned int n, bool used, std::set<CTxDestination>& tx_destinations)
@@ -998,6 +1001,9 @@ CWalletTx* CWallet::AddToWallet(CTransactionRef tx, const TxState& state, const
998
1001
  // Break debit/credit balance caches:
999
1002
  wtx.MarkDirty();
1000
1003
 
1004
+ // since AddToWallet is called directly for self-originating transactions, check for consumption of own coins
1005
+ WalletUpdateSpent(wtx.tx);
1006
+
1001
1007
  // Notify UI of new or updated transaction
1002
1008
  NotifyTransactionChanged(hash, fInsertedNew ? CT_NEW : CT_UPDATED);
1003
1009
 
@@ -1814,8 +1820,13 @@ void CWallet::ReacceptWalletTransactions()
1814
1820
 
1815
1821
  int nDepth = GetTxDepthInMainChain(wtx);
1816
1822
 
1817
- if (!wtx.IsCoinBase() && (nDepth == 0 && !wtx.isAbandoned())) {
1818
- mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx));
1823
+ if (nDepth == 0 && !wtx.isAbandoned()) {
1824
+ if (wtx.IsCoinBase() || wtx.IsCoinStake()) {
1825
+ LogPrintf("Abandoning wtx %s\n", wtx.GetHash().ToString());
1826
+ AbandonTransaction(wtxid);
1827
+ }
1828
+ else
1829
+ mapSorted.insert(std::make_pair(wtx.nOrderPos, &wtx));
1819
1830
  }
1820
1831
  }
1821
1832
 
@@ -1850,7 +1861,7 @@ bool CWallet::SubmitTxMemoryPoolAndRelay(CWalletTx& wtx, std::string& err_string
1850
1861
  // If broadcast fails for any reason, trying to set wtx.m_state here would be incorrect.
1851
1862
  // If transaction was previously in the mempool, it should be updated when
1852
1863
  // TransactionRemovedFromMempool fires.
1853
- bool ret = chain().broadcastTransaction(wtx.tx, m_default_max_tx_fee, relay, err_string);
1864
+ bool ret = chain().broadcastTransaction(wtx.tx, relay, err_string);
1854
1865
  if (ret) wtx.m_state = TxStateInMempool{};
1855
1866
  return ret;
1856
1867
  }
@@ -1939,7 +1950,7 @@ bool CWallet::SignTransaction(CMutableTransaction& tx) const
1939
1950
  }
1940
1951
  const CWalletTx& wtx = mi->second;
1941
1952
  int prev_height = wtx.state<TxStateConfirmed>() ? wtx.state<TxStateConfirmed>()->confirmed_block_height : 0;
1942
- coins[input.prevout] = Coin(wtx.tx->vout[input.prevout.n], prev_height, wtx.IsCoinBase());
1953
+ coins[input.prevout] = Coin(wtx.tx->vout[input.prevout.n], prev_height, wtx.IsCoinBase(), wtx.IsCoinStake(), wtx.nTimeSmart);
1943
1954
  }
1944
1955
  std::map<int, bilingual_str> input_errors;
1945
1956
  return SignTransaction(tx, coins, SIGHASH_DEFAULT, input_errors);
@@ -2790,116 +2801,12 @@ std::shared_ptr<CWallet> CWallet::Create(WalletContext& context, const std::stri
2790
2801
  walletInstance->m_default_change_type = parsed.value();
2791
2802
  }
2792
2803
 
2793
- if (args.IsArgSet("-mintxfee")) {
2794
- std::optional<CAmount> min_tx_fee = ParseMoney(args.GetArg("-mintxfee", ""));
2795
- if (!min_tx_fee || min_tx_fee.value() == 0) {
2796
- error = AmountErrMsg("mintxfee", args.GetArg("-mintxfee", ""));
2797
- return nullptr;
2798
- } else if (min_tx_fee.value() > HIGH_TX_FEE_PER_KB) {
2799
- warnings.push_back(AmountHighWarn("-mintxfee") + Untranslated(" ") +
2800
- _("This is the minimum transaction fee you pay on every transaction."));
2801
- }
2802
-
2803
- walletInstance->m_min_fee = CFeeRate{min_tx_fee.value()};
2804
- }
2805
-
2806
- if (args.IsArgSet("-maxapsfee")) {
2807
- const std::string max_aps_fee{args.GetArg("-maxapsfee", "")};
2808
- if (max_aps_fee == "-1") {
2809
- walletInstance->m_max_aps_fee = -1;
2810
- } else if (std::optional<CAmount> max_fee = ParseMoney(max_aps_fee)) {
2811
- if (max_fee.value() > HIGH_APS_FEE) {
2812
- warnings.push_back(AmountHighWarn("-maxapsfee") + Untranslated(" ") +
2813
- _("This is the maximum transaction fee you pay (in addition to the normal fee) to prioritize partial spend avoidance over regular coin selection."));
2814
- }
2815
- walletInstance->m_max_aps_fee = max_fee.value();
2816
- } else {
2817
- error = AmountErrMsg("maxapsfee", max_aps_fee);
2818
- return nullptr;
2819
- }
2820
- }
2821
-
2822
- if (args.IsArgSet("-fallbackfee")) {
2823
- std::optional<CAmount> fallback_fee = ParseMoney(args.GetArg("-fallbackfee", ""));
2824
- if (!fallback_fee) {
2825
- error = strprintf(_("Invalid amount for -fallbackfee=<amount>: '%s'"), args.GetArg("-fallbackfee", ""));
2826
- return nullptr;
2827
- } else if (fallback_fee.value() > HIGH_TX_FEE_PER_KB) {
2828
- warnings.push_back(AmountHighWarn("-fallbackfee") + Untranslated(" ") +
2829
- _("This is the transaction fee you may pay when fee estimates are not available."));
2830
- }
2831
- walletInstance->m_fallback_fee = CFeeRate{fallback_fee.value()};
2832
- }
2833
-
2834
- // Disable fallback fee in case value was set to 0, enable if non-null value
2835
- walletInstance->m_allow_fallback_fee = walletInstance->m_fallback_fee.GetFeePerK() != 0;
2836
-
2837
- if (args.IsArgSet("-discardfee")) {
2838
- std::optional<CAmount> discard_fee = ParseMoney(args.GetArg("-discardfee", ""));
2839
- if (!discard_fee) {
2840
- error = strprintf(_("Invalid amount for -discardfee=<amount>: '%s'"), args.GetArg("-discardfee", ""));
2841
- return nullptr;
2842
- } else if (discard_fee.value() > HIGH_TX_FEE_PER_KB) {
2843
- warnings.push_back(AmountHighWarn("-discardfee") + Untranslated(" ") +
2844
- _("This is the transaction fee you may discard if change is smaller than dust at this level"));
2845
- }
2846
- walletInstance->m_discard_rate = CFeeRate{discard_fee.value()};
2847
- }
2848
-
2849
- if (args.IsArgSet("-paytxfee")) {
2850
- std::optional<CAmount> pay_tx_fee = ParseMoney(args.GetArg("-paytxfee", ""));
2851
- if (!pay_tx_fee) {
2852
- error = AmountErrMsg("paytxfee", args.GetArg("-paytxfee", ""));
2853
- return nullptr;
2854
- } else if (pay_tx_fee.value() > HIGH_TX_FEE_PER_KB) {
2855
- warnings.push_back(AmountHighWarn("-paytxfee") + Untranslated(" ") +
2856
- _("This is the transaction fee you will pay if you send a transaction."));
2857
- }
2858
-
2859
- walletInstance->m_pay_tx_fee = CFeeRate{pay_tx_fee.value(), 1000};
2860
-
2861
- if (chain && walletInstance->m_pay_tx_fee < chain->relayMinFee()) {
2862
- error = strprintf(_("Invalid amount for -paytxfee=<amount>: '%s' (must be at least %s)"),
2863
- args.GetArg("-paytxfee", ""), chain->relayMinFee().ToString());
2864
- return nullptr;
2865
- }
2866
- }
2867
-
2868
- if (args.IsArgSet("-maxtxfee")) {
2869
- std::optional<CAmount> max_fee = ParseMoney(args.GetArg("-maxtxfee", ""));
2870
- if (!max_fee) {
2871
- error = AmountErrMsg("maxtxfee", args.GetArg("-maxtxfee", ""));
2872
- return nullptr;
2873
- } else if (max_fee.value() > HIGH_MAX_TX_FEE) {
2874
- warnings.push_back(_("-maxtxfee is set very high! Fees this large could be paid on a single transaction."));
2875
- }
2876
-
2877
- if (chain && CFeeRate{max_fee.value(), 1000} < chain->relayMinFee()) {
2878
- error = strprintf(_("Invalid amount for -maxtxfee=<amount>: '%s' (must be at least the minrelay fee of %s to prevent stuck transactions)"),
2879
- args.GetArg("-maxtxfee", ""), chain->relayMinFee().ToString());
2880
- return nullptr;
2881
- }
2882
-
2883
- walletInstance->m_default_max_tx_fee = max_fee.value();
2884
- }
2885
-
2886
- if (args.IsArgSet("-consolidatefeerate")) {
2887
- if (std::optional<CAmount> consolidate_feerate = ParseMoney(args.GetArg("-consolidatefeerate", ""))) {
2888
- walletInstance->m_consolidate_feerate = CFeeRate(*consolidate_feerate);
2889
- } else {
2890
- error = AmountErrMsg("consolidatefeerate", args.GetArg("-consolidatefeerate", ""));
2891
- return nullptr;
2892
- }
2893
- }
2894
-
2895
- if (chain && chain->relayMinFee().GetFeePerK() > HIGH_TX_FEE_PER_KB) {
2896
- warnings.push_back(AmountHighWarn("-minrelaytxfee") + Untranslated(" ") +
2897
- _("The wallet will avoid paying less than the minimum relay fee."));
2898
- }
2899
-
2900
- walletInstance->m_confirm_target = args.GetIntArg("-txconfirmtarget", DEFAULT_TX_CONFIRM_TARGET);
2901
2804
  walletInstance->m_spend_zero_conf_change = args.GetBoolArg("-spendzeroconfchange", DEFAULT_SPEND_ZEROCONF_CHANGE);
2902
- walletInstance->m_signal_rbf = args.GetBoolArg("-walletrbf", DEFAULT_WALLET_RBF);
2805
+ walletInstance->m_split_coins = args.GetBoolArg("-splitcoins", DEFAULT_SPLIT_COINS);
2806
+ walletInstance->WalletLogPrintf("Wallet will%s split coins during minting\n", walletInstance->m_split_coins? "" : " not");
2807
+
2808
+ walletInstance->m_check_github = args.GetBoolArg("-checkgithub", DEFAULT_CHECK_GITHUB);
2809
+ walletInstance->WalletLogPrintf("Wallet will%s check github for newer version on startup\n", walletInstance->m_check_github? "" : " not");
2903
2810
 
2904
2811
  walletInstance->WalletLogPrintf("Wallet completed loading in %15dms\n", GetTimeMillis() - nStart);
2905
2812
 
@@ -2962,24 +2869,6 @@ bool CWallet::AttachChain(const std::shared_ptr<CWallet>& walletInstance, interf
2962
2869
 
2963
2870
  if (tip_height && *tip_height != rescan_height)
2964
2871
  {
2965
- if (chain.havePruned()) {
2966
- int block_height = *tip_height;
2967
- while (block_height > 0 && chain.haveBlockOnDisk(block_height - 1) && rescan_height != block_height) {
2968
- --block_height;
2969
- }
2970
-
2971
- if (rescan_height != block_height) {
2972
- // We can't rescan beyond non-pruned blocks, stop and throw an error.
2973
- // This might happen if a user uses an old wallet within a pruned node
2974
- // or if they ran -disablewallet for a longer time, then decided to re-enable
2975
- // Exit early and print an error.
2976
- // If a block is pruned after this check, we will load the wallet,
2977
- // but fail the rescan with a generic error.
2978
- error = _("Prune: last wallet synchronisation goes beyond pruned data. You need to -reindex (download the whole blockchain again in case of pruned node)");
2979
- return false;
2980
- }
2981
- }
2982
-
2983
2872
  chain.initMessage(_("Rescanning…").translated);
2984
2873
  walletInstance->WalletLogPrintf("Rescanning last %i blocks (from block %i)...\n", *tip_height - rescan_height, rescan_height);
2985
2874
 
@@ -3097,11 +2986,12 @@ int CWallet::GetTxDepthInMainChain(const CWalletTx& wtx) const
3097
2986
 
3098
2987
  int CWallet::GetTxBlocksToMaturity(const CWalletTx& wtx) const
3099
2988
  {
3100
- if (!wtx.IsCoinBase())
2989
+ if (!(wtx.IsCoinBase() || wtx.IsCoinStake()))
3101
2990
  return 0;
3102
2991
  int chain_depth = GetTxDepthInMainChain(wtx);
3103
- assert(chain_depth >= 0); // coinbase tx should not be conflicted
3104
- return std::max(0, (COINBASE_MATURITY+1) - chain_depth);
2992
+ if (!wtx.IsCoinStake())
2993
+ assert(chain_depth >= 0); // coinbase tx should not be conflicted
2994
+ return std::max(0, (Params().GetConsensus().nCoinbaseMaturity+1) - chain_depth);
3105
2995
  }
3106
2996
 
3107
2997
  bool CWallet::IsTxImmatureCoinBase(const CWalletTx& wtx) const
@@ -3272,6 +3162,277 @@ void CWallet::ConnectScriptPubKeyManNotifiers()
3272
3162
  }
3273
3163
  }
3274
3164
 
3165
+ // peercoin: create coin stake transaction
3166
+ typedef std::vector<unsigned char> valtype;
3167
+ bool CWallet::CreateCoinStake(ChainstateManager& chainman, const CWallet* pwallet, unsigned int nBits, int64_t nSearchInterval, CMutableTransaction& txNew)
3168
+ {
3169
+ bool bDebug = (gArgs.GetBoolArg("-debug", false) && gArgs.GetBoolArg("-printcoinstake", false));
3170
+ // if there are pre signed coinstakes, we'll use them for minting
3171
+ if (m_coinstakes.size()) {
3172
+
3173
+ uint32_t nTime = GetTime();
3174
+ if (bDebug)
3175
+ LogPrintf("there are imported coinstakes, time is %d, nSearchInterval %d\n", nTime, nSearchInterval);
3176
+
3177
+ for (const auto& [timestamp, txn] : m_coinstakes) {
3178
+ // check timestamp
3179
+ if (nTime > timestamp) {
3180
+ if (nTime - nSearchInterval <= timestamp) {
3181
+ if (bDebug)
3182
+ LogPrintf("timestamp within nSearchInterval, using coinstake\n");
3183
+ CMutableTransaction presigned(*txn);
3184
+ txNew = presigned;
3185
+ return true;
3186
+ }
3187
+ else {
3188
+ if (bDebug)
3189
+ LogPrintf("timestamp too old, removing coinstake\n");
3190
+ m_coinstakes.erase(timestamp);
3191
+ break;
3192
+ }
3193
+ }
3194
+ }
3195
+ }
3196
+
3197
+ // The following split & combine thresholds are important to security
3198
+ // Should not be adjusted if you don't understand the consequences
3199
+ static unsigned int nStakeSplitAge = (60 * 60 * 24 * 90);
3200
+ int64_t nCombineThreshold = GetProofOfWorkReward(GetLastBlockIndex(chainman.ActiveChain().Tip(), false)->nBits, txNew.nTime) / 3;
3201
+
3202
+ CBigNum bnTargetPerCoinDay;
3203
+ bnTargetPerCoinDay.SetCompact(nBits);
3204
+
3205
+ // Transaction index is required to get to block header
3206
+ if (!g_txindex)
3207
+ return error("CreateCoinStake : transaction index unavailable");
3208
+ const Consensus::Params& params = Params().GetConsensus();
3209
+
3210
+ LOCK2(cs_main, pwallet->cs_wallet);
3211
+ txNew.vin.clear();
3212
+ txNew.vout.clear();
3213
+ // Mark coin stake transaction
3214
+ CScript scriptEmpty;
3215
+ scriptEmpty.clear();
3216
+ txNew.vout.push_back(CTxOut(0, scriptEmpty));
3217
+ // Choose coins to use
3218
+ CAmount nBalance = GetBalance(*this).m_mine_trusted;
3219
+ std::optional<CAmount> nReserveBalance = ParseMoney(gArgs.GetArg("-reservebalance", ""));
3220
+ if (gArgs.IsArgSet("-reservebalance") && !nReserveBalance)
3221
+ return error("CreateCoinStake : invalid reserve balance amount");
3222
+ if (nBalance <= nReserveBalance)
3223
+ return false;
3224
+ std::vector<CTransactionRef> vwtxPrev;
3225
+ CAmount nValueIn = 0;
3226
+ std::vector<COutput> vAvailableCoins;
3227
+ CCoinControl temp;
3228
+ CoinSelectionParams coin_selection_params;
3229
+ coin_selection_params.m_subtract_fee_outputs = true;
3230
+
3231
+ bool bnb_used;
3232
+ AvailableCoins(*pwallet, vAvailableCoins, &temp);
3233
+
3234
+ CAmount nAllowedBalance = nBalance;
3235
+ if (nReserveBalance) nAllowedBalance -= nReserveBalance.value();
3236
+
3237
+ std::optional<SelectionResult> result = SelectCoins(*pwallet, vAvailableCoins, nAllowedBalance, temp, coin_selection_params);
3238
+
3239
+ if (!result)
3240
+ return false;
3241
+
3242
+ CAmount nCredit = 0;
3243
+ CScript scriptPubKeyKernel;
3244
+
3245
+ for (const auto& pcoin : result->GetInputSet())
3246
+ {
3247
+ CDiskTxPos postx;
3248
+ if (!g_txindex->FindTxPosition(pcoin.outpoint.hash, postx))
3249
+ continue;
3250
+
3251
+ CBlockHeader header;
3252
+ CTransactionRef tx;
3253
+ auto it = g_txindex->cachedTxs.find(pcoin.outpoint.hash);
3254
+ if (it != g_txindex->cachedTxs.end()) {
3255
+ header = it->second.first;
3256
+ tx = it->second.second;
3257
+ } else {
3258
+ try {
3259
+ // Read block header
3260
+ CAutoFile file(node::OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
3261
+ file >> header;
3262
+ fseek(file.Get(), postx.nTxOffset, SEEK_CUR);
3263
+ file >> tx;
3264
+ g_txindex->cachedTxs[pcoin.outpoint.hash]=std::pair(header,tx);
3265
+ } catch (std::exception &e) {
3266
+ return error("%s() : deserialize or I/O error in CreateCoinStake()", __PRETTY_FUNCTION__);
3267
+ }
3268
+ }
3269
+
3270
+ static int nMaxStakeSearchInterval = 60;
3271
+ if (header.GetBlockTime() + params.nStakeMinAge > txNew.nTime - nMaxStakeSearchInterval)
3272
+ continue; // only count coins meeting min age requirement
3273
+
3274
+ bool fKernelFound = false;
3275
+ for (unsigned int n=0; n<std::min(nSearchInterval,(int64_t)nMaxStakeSearchInterval) && !fKernelFound; n++)
3276
+ {
3277
+ // Search backward in time from the given txNew timestamp
3278
+ // Search nSearchInterval seconds back up to nMaxStakeSearchInterval
3279
+ uint256 hashProofOfStake = uint256();
3280
+ COutPoint prevoutStake = pcoin.outpoint;
3281
+ if (CheckStakeKernelHash(nBits, chainman.ActiveChain().Tip(), header, postx.nTxOffset + CBlockHeader::NORMAL_SERIALIZE_SIZE, tx, prevoutStake, txNew.nTime - n, hashProofOfStake, false, chainman.ActiveChainstate()))
3282
+ {
3283
+ // Found a kernel
3284
+ if (bDebug)
3285
+ LogPrintf("CreateCoinStake : kernel found\n");
3286
+ std::vector<valtype> vSolutions;
3287
+ TxoutType whichType;
3288
+ CScript scriptPubKeyOut;
3289
+ scriptPubKeyKernel = pcoin.txout.scriptPubKey;
3290
+ whichType = Solver(scriptPubKeyKernel, vSolutions);
3291
+
3292
+ if (bDebug)
3293
+ LogPrintf("CreateCoinStake : parsed kernel type=%s\n", GetTxnOutputType(whichType));
3294
+ if (whichType != TxoutType::PUBKEY && whichType != TxoutType::PUBKEYHASH && whichType != TxoutType::WITNESS_V0_KEYHASH)
3295
+ {
3296
+ if (bDebug)
3297
+ LogPrintf("CreateCoinStake : no support for kernel type=%s\n", GetTxnOutputType(whichType));
3298
+ break; // only support pay to public key and pay to address and pay to witness keyhash
3299
+ }
3300
+ if (whichType == TxoutType::PUBKEYHASH || whichType == TxoutType::WITNESS_V0_KEYHASH) // pay to address type or witness keyhash
3301
+ {
3302
+ // convert to pay to public key type
3303
+ CKey key;
3304
+ if (!pwallet->GetLegacyScriptPubKeyMan()->GetKey(CKeyID(uint160(vSolutions[0])), key))
3305
+ {
3306
+ if (bDebug)
3307
+ LogPrintf("CreateCoinStake : failed to get key for kernel type=%s\n", GetTxnOutputType(whichType));
3308
+ break; // unable to find corresponding public key
3309
+ }
3310
+ scriptPubKeyOut << ToByteVector(key.GetPubKey()) << OP_CHECKSIG;
3311
+ }
3312
+ else
3313
+ scriptPubKeyOut = scriptPubKeyKernel;
3314
+
3315
+ txNew.nTime -= n;
3316
+ txNew.vin.push_back(CTxIn(pcoin.outpoint.hash, pcoin.outpoint.n));
3317
+ nCredit += pcoin.txout.nValue;
3318
+ vwtxPrev.push_back(tx);
3319
+ txNew.vout.push_back(CTxOut(0, scriptPubKeyOut));
3320
+ if ((header.GetBlockTime() + nStakeSplitAge > txNew.nTime) && pwallet->m_split_coins)
3321
+ txNew.vout.push_back(CTxOut(0, scriptPubKeyOut)); //split stake
3322
+ if (bDebug)
3323
+ LogPrintf("CreateCoinStake : added kernel type=%s\n", GetTxnOutputType(whichType));
3324
+ fKernelFound = true;
3325
+ break;
3326
+ }
3327
+ }
3328
+ if (fKernelFound)
3329
+ break; // if kernel is found stop searching
3330
+ }
3331
+ if (nCredit == 0 || nCredit > nAllowedBalance)
3332
+ return false;
3333
+ for (const auto& pcoin : result->GetInputSet())
3334
+ {
3335
+ CDiskTxPos postx;
3336
+ if (!g_txindex->FindTxPosition(pcoin.outpoint.hash, postx))
3337
+ continue;
3338
+
3339
+ // Read block header
3340
+ CAutoFile file(node::OpenBlockFile(postx, true), SER_DISK, CLIENT_VERSION);
3341
+ CBlockHeader header;
3342
+ CTransactionRef tx;
3343
+ try {
3344
+ file >> header;
3345
+ fseek(file.Get(), postx.nTxOffset, SEEK_CUR);
3346
+ file >> tx;
3347
+ } catch (std::exception &e) {
3348
+ return error("%s() : deserialize or I/O error in CreateCoinStake()", __PRETTY_FUNCTION__);
3349
+ }
3350
+
3351
+
3352
+ // Attempt to add more inputs
3353
+ // Only add coins of the same key/address as kernel
3354
+ if (txNew.vout.size() == 2 && ((pcoin.txout.scriptPubKey == scriptPubKeyKernel || pcoin.txout.scriptPubKey == txNew.vout[1].scriptPubKey))
3355
+ && pcoin.outpoint.hash != txNew.vin[0].prevout.hash)
3356
+ {
3357
+ // Stop adding more inputs if already too many inputs
3358
+ if (txNew.vin.size() >= 100)
3359
+ break;
3360
+ // Stop adding more inputs if value is already pretty significant
3361
+ if (nCredit > nCombineThreshold)
3362
+ break;
3363
+ // Stop adding inputs if reached reserve limit
3364
+ if (nCredit + pcoin.txout.nValue > nBalance - nReserveBalance.value())
3365
+ break;
3366
+ // Do not add additional significant input
3367
+ if (pcoin.txout.nValue > nCombineThreshold)
3368
+ continue;
3369
+ // Do not add input that is still too young
3370
+ if (tx->nTime + params.nStakeMaxAge > txNew.nTime)
3371
+ continue;
3372
+ txNew.vin.push_back(CTxIn(pcoin.outpoint.hash, pcoin.outpoint.n));
3373
+ nCredit += pcoin.txout.nValue;
3374
+ vwtxPrev.push_back(tx);
3375
+ }
3376
+ }
3377
+ // Calculate coin age reward
3378
+ {
3379
+ uint64_t nCoinAge;
3380
+ CCoinsViewCache view(&chainman.ActiveChainstate().CoinsTip());
3381
+ if (!GetCoinAge((const CTransaction)txNew, view, nCoinAge, txNew.nTime, true))
3382
+ return error("CreateCoinStake : failed to calculate coin age");
3383
+
3384
+ CAmount nReward = GetProofOfStakeReward(nCoinAge, txNew.nTime, chainman.ActiveChain().Tip()->nMoneySupply);
3385
+ // Refuse to create mint that has zero or negative reward
3386
+ if(nReward <= 0) {
3387
+ return false;
3388
+ }
3389
+ nCredit += nReward;
3390
+ }
3391
+
3392
+ CAmount nMinFee = 0;
3393
+ CAmount nMinFeeBase = (IsProtocolV07(txNew.nTime) ? MIN_TX_FEE : MIN_TX_FEE_PREV7);
3394
+ while(true)
3395
+ {
3396
+ // Set output amount
3397
+ if (txNew.vout.size() == 3)
3398
+ {
3399
+ txNew.vout[1].nValue = ((nCredit - nMinFee) / 2 / nMinFeeBase) * nMinFeeBase;
3400
+ txNew.vout[2].nValue = nCredit - nMinFee - txNew.vout[1].nValue;
3401
+ }
3402
+ else
3403
+ txNew.vout[1].nValue = nCredit - nMinFee;
3404
+
3405
+ // Sign
3406
+ int nIn = 0;
3407
+ for (const auto& pcoin : vwtxPrev)
3408
+ {
3409
+ if (!SignSignature(*pwallet->GetLegacyScriptPubKeyMan(), *pcoin, txNew, nIn++, SIGHASH_ALL))
3410
+ return error("CreateCoinStake : failed to sign coinstake");
3411
+ }
3412
+
3413
+ // Limit size
3414
+ unsigned int nBytes = ::GetSerializeSize(txNew, SER_NETWORK, PROTOCOL_VERSION);
3415
+ if (nBytes >= 1000000/5)
3416
+ return error("CreateCoinStake : exceeded coinstake size limit");
3417
+
3418
+ // Check enough fee is paid
3419
+ if (nMinFee < GetMinFee(CTransaction(txNew), txNew.nTime) - nMinFeeBase)
3420
+ {
3421
+ nMinFee = GetMinFee(CTransaction(txNew), txNew.nTime) - nMinFeeBase;
3422
+ continue; // try signing again
3423
+ }
3424
+ else
3425
+ {
3426
+ if (bDebug)
3427
+ LogPrintf("CreateCoinStake : fee for coinstake %s\n", FormatMoney(nMinFee).c_str());
3428
+ break;
3429
+ }
3430
+ }
3431
+
3432
+ // Successfully generated coinstake
3433
+ return true;
3434
+ }
3435
+
3275
3436
  void CWallet::LoadDescriptorScriptPubKeyMan(uint256 id, WalletDescriptor& desc)
3276
3437
  {
3277
3438
  if (IsWalletFlagSet(WALLET_FLAG_EXTERNAL_SIGNER)) {
src/wallet/wallet.h CHANGED
@@ -7,11 +7,11 @@
7
7
  #define BITCOIN_WALLET_WALLET_H
8
8
 
9
9
  #include <consensus/amount.h>
10
+ #include <consensus/tx_verify.h>
10
11
  #include <fs.h>
11
12
  #include <interfaces/chain.h>
12
13
  #include <interfaces/handler.h>
13
14
  #include <outputtype.h>
14
- #include <policy/feerate.h>
15
15
  #include <psbt.h>
16
16
  #include <tinyformat.h>
17
17
  #include <util/message.h>
@@ -19,6 +19,7 @@
19
19
  #include <util/string.h>
20
20
  #include <util/system.h>
21
21
  #include <util/ui_change_type.h>
22
+ #include <validation.h>
22
23
  #include <validationinterface.h>
23
24
  #include <wallet/coinselection.h>
24
25
  #include <wallet/crypter.h>
@@ -46,7 +47,6 @@ using LoadWalletFn = std::function<void(std::unique_ptr<interfaces::Wallet> wall
46
47
 
47
48
  class CScript;
48
49
  enum class FeeEstimateMode;
49
- struct FeeCalculation;
50
50
  struct bilingual_str;
51
51
 
52
52
  namespace wallet {
@@ -71,14 +71,9 @@ std::unique_ptr<interfaces::Handler> HandleLoadWallet(WalletContext& context, Lo
71
71
  void NotifyWalletLoaded(WalletContext& context, const std::shared_ptr<CWallet>& wallet);
72
72
  std::unique_ptr<WalletDatabase> MakeWalletDatabase(const std::string& name, const DatabaseOptions& options, DatabaseStatus& status, bilingual_str& error);
73
73
 
74
- //! -paytxfee default
75
- constexpr CAmount DEFAULT_PAY_TX_FEE = 0;
76
- //! -fallbackfee default
77
- static const CAmount DEFAULT_FALLBACK_FEE = 0;
78
- //! -discardfee default
79
- static const CAmount DEFAULT_DISCARD_FEE = 10000;
80
- //! -mintxfee default
81
- static const CAmount DEFAULT_TRANSACTION_MINFEE = 1000;
74
+ extern bool fWalletUnlockMintOnly;
75
+
76
+ static const CAmount MIN_CHANGE = MIN_TXOUT_AMOUNT;
82
77
  //! -consolidatefeerate default
83
78
  static const CAmount DEFAULT_CONSOLIDATE_FEERATE{10000}; // 10 sat/vbyte
84
79
  /**
@@ -91,24 +86,18 @@ static const CAmount DEFAULT_CONSOLIDATE_FEERATE{10000}; // 10 sat/vbyte
91
86
  static const CAmount DEFAULT_MAX_AVOIDPARTIALSPEND_FEE = 0;
92
87
  //! discourage APS fee higher than this amount
93
88
  constexpr CAmount HIGH_APS_FEE{COIN / 10000};
94
- //! minimum recommended increment for BIP 125 replacement txs
95
- static const CAmount WALLET_INCREMENTAL_RELAY_FEE = 5000;
96
89
  //! Default for -spendzeroconfchange
97
90
  static const bool DEFAULT_SPEND_ZEROCONF_CHANGE = true;
91
+ //! Default for -splitcoins
92
+ static const bool DEFAULT_SPLIT_COINS = true;
93
+ //! Default for -checkgithub
94
+ static const bool DEFAULT_CHECK_GITHUB = true;
98
95
  //! Default for -walletrejectlongchains
99
96
  static const bool DEFAULT_WALLET_REJECT_LONG_CHAINS = false;
100
97
  //! -txconfirmtarget default
101
98
  static const unsigned int DEFAULT_TX_CONFIRM_TARGET = 6;
102
- //! -walletrbf default
103
- static const bool DEFAULT_WALLET_RBF = false;
104
99
  static const bool DEFAULT_WALLETBROADCAST = true;
105
100
  static const bool DEFAULT_DISABLE_WALLET = false;
106
- //! -maxtxfee default
107
- constexpr CAmount DEFAULT_TRANSACTION_MAXFEE{COIN / 10};
108
- //! Discourage users to set fees higher than this amount (in satoshis) per kB
109
- constexpr CAmount HIGH_TX_FEE_PER_KB{COIN / 100};
110
- //! -maxtxfee will warn if called with a higher fee than this amount (in satoshis)
111
- constexpr CAmount HIGH_MAX_TX_FEE{100 * HIGH_TX_FEE_PER_KB};
112
101
  //! Pre-calculated constants for input size estimation in *virtual size*
113
102
  static constexpr size_t DUMMY_NESTED_P2WPKH_INPUT_SIZE = 91;
114
103
 
@@ -118,7 +107,7 @@ class CWalletTx;
118
107
  class ReserveDestination;
119
108
 
120
109
  //! Default for -addresstype
121
- constexpr OutputType DEFAULT_ADDRESS_TYPE{OutputType::BECH32};
110
+ constexpr OutputType DEFAULT_ADDRESS_TYPE{OutputType::LEGACY};
122
111
 
123
112
  static constexpr uint64_t KNOWN_WALLET_FLAGS =
124
113
  WALLET_FLAG_AVOID_REUSE
@@ -401,6 +390,8 @@ public:
401
390
  std::map<CTxDestination, CAddressBookData> m_address_book GUARDED_BY(cs_wallet);
402
391
  const CAddressBookData* FindAddressBookEntry(const CTxDestination&, bool allow_change = false) const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
403
392
 
393
+ std::map<uint32_t, CTransactionRef> m_coinstakes;
394
+
404
395
  /** Set of Coins owned by this wallet that we won't try to spend from. A
405
396
  * Coin may be locked if it has already been used to fund a transaction
406
397
  * that hasn't confirmed yet. We wouldn't consider the Coin spent already,
@@ -503,6 +494,7 @@ public:
503
494
  int64_t IncOrderPosNext(WalletBatch *batch = nullptr) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
504
495
  DBErrors ReorderTransactions();
505
496
 
497
+ void WalletUpdateSpent(const CTransactionRef& tx);
506
498
  void MarkDirty();
507
499
 
508
500
  //! Callback for updating transaction metadata in mapWallet.
@@ -582,6 +574,7 @@ public:
582
574
  * @param[in] orderForm BIP 70 / BIP 21 order form details to be set on the transaction.
583
575
  */
584
576
  void CommitTransaction(CTransactionRef tx, mapValue_t mapValue, std::vector<std::pair<std::string, std::string>> orderForm);
577
+ bool CreateCoinStake(ChainstateManager& chainman, const CWallet* pwallet, unsigned int nBits, int64_t nSearchInterval, CMutableTransaction &txNew);
585
578
 
586
579
  /** Pass this transaction to node for mempool insertion and relay to peers if flag set to true */
587
580
  bool SubmitTxMemoryPoolAndRelay(CWalletTx& wtx, std::string& err_string, bool relay) const;
@@ -599,30 +592,11 @@ public:
599
592
  bool ImportPubKeys(const std::vector<CKeyID>& ordered_pubkeys, const std::map<CKeyID, CPubKey>& pubkey_map, const std::map<CKeyID, std::pair<CPubKey, KeyOriginInfo>>& key_origins, const bool add_keypool, const bool internal, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
600
593
  bool ImportScriptPubKeys(const std::string& label, const std::set<CScript>& script_pub_keys, const bool have_solving_data, const bool apply_label, const int64_t timestamp) EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
601
594
 
602
- CFeeRate m_pay_tx_fee{DEFAULT_PAY_TX_FEE};
603
- unsigned int m_confirm_target{DEFAULT_TX_CONFIRM_TARGET};
604
595
  /** Allow Coin Selection to pick unconfirmed UTXOs that were sent from our own wallet if it
605
596
  * cannot fund the transaction otherwise. */
606
597
  bool m_spend_zero_conf_change{DEFAULT_SPEND_ZEROCONF_CHANGE};
607
- bool m_signal_rbf{DEFAULT_WALLET_RBF};
608
- bool m_allow_fallback_fee{true}; //!< will be false if -fallbackfee=0
609
- CFeeRate m_min_fee{DEFAULT_TRANSACTION_MINFEE}; //!< Override with -mintxfee
610
- /**
611
- * If fee estimation does not have enough data to provide estimates, use this fee instead.
612
- * Has no effect if not using fee estimation
613
- * Override with -fallbackfee
614
- */
615
- CFeeRate m_fallback_fee{DEFAULT_FALLBACK_FEE};
616
-
617
- /** If the cost to spend a change output at this feerate is greater than the value of the
618
- * output itself, just drop it to fees. */
619
- CFeeRate m_discard_rate{DEFAULT_DISCARD_FEE};
620
-
621
- /** When the actual feerate is less than the consolidate feerate, we will tend to make transactions which
622
- * consolidate inputs. When the actual feerate is greater than the consolidate feerate, we will tend to make
623
- * transactions which have the lowest fees.
624
- */
625
- CFeeRate m_consolidate_feerate{DEFAULT_CONSOLIDATE_FEERATE};
598
+ bool m_split_coins{DEFAULT_SPLIT_COINS};
599
+ bool m_check_github{DEFAULT_CHECK_GITHUB};
626
600
 
627
601
  /** The maximum fee amount we're willing to pay to prioritize partial spend avoidance. */
628
602
  CAmount m_max_aps_fee{DEFAULT_MAX_AVOIDPARTIALSPEND_FEE}; //!< note: this is absolute fee, not fee rate
@@ -634,8 +608,6 @@ public:
634
608
  * CWallet::TransactionChangeType for details).
635
609
  */
636
610
  std::optional<OutputType> m_default_change_type{};
637
- /** Absolute maximum transaction fee (in satoshis) used by default for the wallet */
638
- CAmount m_default_max_tx_fee{DEFAULT_TRANSACTION_MAXFEE};
639
611
 
640
612
  size_t KeypoolCountExternalKeys() const EXCLUSIVE_LOCKS_REQUIRED(cs_wallet);
641
613
  bool TopUpKeyPool(unsigned int kpSize = 0);
@@ -744,8 +716,6 @@ public:
744
716
  /* Mark a transaction (and it in-wallet descendants) as abandoned so its inputs may be respent. */
745
717
  bool AbandonTransaction(const uint256& hashTx);
746
718
 
747
- /** Mark a transaction as replaced by another transaction (e.g., BIP 125). */
748
- bool MarkReplaced(const uint256& originalHash, const uint256& newHash);
749
719
 
750
720
  /* Initializes the wallet, returns a new CWallet instance or a null pointer in case of an error */
751
721
  static std::shared_ptr<CWallet> Create(WalletContext& context, const std::string& name, std::unique_ptr<WalletDatabase> database, uint64_t wallet_creation_flags, bilingual_str& error, std::vector<bilingual_str>& warnings);
src/wallet/walletdb.h CHANGED
@@ -7,6 +7,7 @@
7
7
  #define BITCOIN_WALLET_WALLETDB_H
8
8
 
9
9
  #include <script/sign.h>
10
+ #include <wallet/context.h>
10
11
  #include <wallet/db.h>
11
12
  #include <wallet/walletutil.h>
12
13
  #include <key.h>
@@ -25,7 +26,7 @@ class CKeyPool;
25
26
  class CMasterKey;
26
27
  class CWallet;
27
28
  class CWalletTx;
28
- struct WalletContext;
29
+ //struct WalletContext;
29
30
 
30
31
  /**
31
32
  * Overview of wallet database classes:
src/warnings.cpp CHANGED
@@ -15,6 +15,7 @@
15
15
  static Mutex g_warnings_mutex;
16
16
  static bilingual_str g_misc_warnings GUARDED_BY(g_warnings_mutex);
17
17
  static bool fLargeWorkInvalidChainFound GUARDED_BY(g_warnings_mutex) = false;
18
+ std::string strMintWarning;
18
19
 
19
20
  void SetMiscWarning(const bilingual_str& warning)
20
21
  {
@@ -41,6 +42,13 @@ bilingual_str GetWarnings(bool verbose)
41
42
  warnings_verbose.emplace_back(warnings_concise);
42
43
  }
43
44
 
45
+ // peercoin: wallet lock warning for minting
46
+ if (strMintWarning != "")
47
+ {
48
+ warnings_concise = Untranslated(strMintWarning);
49
+ warnings_verbose.emplace_back(warnings_concise);
50
+ }
51
+
44
52
  // Misc warnings like out of disk space and clock is wrong
45
53
  if (!g_misc_warnings.empty()) {
46
54
  warnings_concise = g_misc_warnings;
src/warnings.h CHANGED
@@ -20,4 +20,5 @@ void SetfLargeWorkInvalidChainFound(bool flag);
20
20
  */
21
21
  bilingual_str GetWarnings(bool verbose);
22
22
 
23
+ extern std::string strMintWarning;
23
24
  #endif // BITCOIN_WARNINGS_H